├── .eslintrc.json ├── .gitignore ├── README.md ├── next.config.mjs ├── package-lock.json ├── package.json ├── postcss.config.mjs ├── public ├── chapter1 │ ├── bulb-off.png │ ├── bulb-on.png │ ├── cat_reaching.png │ ├── cover.jpg │ ├── one.png │ ├── rule1.jpg │ ├── rule2.jpg │ └── zero.png ├── chapter2 │ └── ascii.jpg ├── chapter3 │ ├── mario.png │ ├── pixelart.jpg │ └── starwar.png ├── evergreen_avatar.png ├── flamey_avatar.png ├── font-sprite.svg ├── icon.svg ├── sitemap.xml └── starlaxverse_avatar.png ├── src ├── components │ ├── chapter0 │ │ └── Chapter0.tsx │ ├── chapter1 │ │ ├── Chapter1.tsx │ │ ├── Cover.jsx │ │ ├── FourSwitches.tsx │ │ ├── Legos.tsx │ │ ├── PlaceValues.tsx │ │ ├── Poem.tsx │ │ ├── Rule1.tsx │ │ ├── Rule2.tsx │ │ ├── Rule3.tsx │ │ └── Switch.tsx │ ├── chapter2 │ │ ├── Answer.tsx │ │ ├── AsciiTable.tsx │ │ ├── Chapter2.tsx │ │ ├── Code.tsx │ │ └── Hex.tsx │ ├── chapter3 │ │ ├── Chapter3.tsx │ │ ├── RGB.tsx │ │ └── RGB2.tsx │ ├── common │ │ ├── BounceButton.tsx │ │ ├── NextButton.tsx │ │ ├── renderParagraphs.tsx │ │ ├── transition.css │ │ ├── transition.jsx │ │ ├── types.ts │ │ └── withCover.jsx │ └── demo │ │ ├── AnimatedFIFOList.jsx │ │ ├── Bmp.jsx │ │ ├── ClockFont.tsx │ │ └── DigitalSignalWave.jsx ├── global.css ├── pages │ ├── _app.tsx │ ├── _document.tsx │ ├── api │ │ ├── chat.ts │ │ └── token.ts │ ├── chapter0 │ │ └── index.tsx │ ├── chapter1 │ │ ├── chat.tsx │ │ └── index.tsx │ ├── chapter2 │ │ ├── chat.tsx │ │ └── index.tsx │ ├── chapter3 │ │ ├── chat.tsx │ │ └── index.tsx │ ├── chapter4 │ │ └── index.tsx │ ├── demo │ │ └── index.tsx │ └── index.tsx ├── react-chat │ ├── ChatRoom.tsx │ └── TypingIndicator.tsx └── react-snowfall │ ├── Snowfall.js │ ├── SnowfallCanvas.js │ ├── Snowflake.js │ ├── config.js │ ├── hooks.js │ ├── index.js │ └── utils.js ├── tailwind.config.ts └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "rules": { 4 | "react/no-unescaped-entities": "off" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | .vscode 3 | 4 | # dependencies 5 | /node_modules 6 | /.pnp 7 | .pnp.js 8 | .yarn/install-state.gz 9 | 10 | # testing 11 | /coverage 12 | 13 | # next.js 14 | /.next/ 15 | /out/ 16 | 17 | # production 18 | /build 19 | 20 | # misc 21 | .DS_Store 22 | *.pem 23 | 24 | # debug 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | 29 | # local env files 30 | .env*.local 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lost Language of the Machines 2 | 3 | _This book is currently in the creation phase._ 4 | 5 | ## Introduction 6 | In a world half a millennium in the future, where computer science as we know it has become the stuff of legends, two unlikely students embark on a journey through the annals of ‘ancient’ programming. 7 | 8 | ## Meet the characters 9 | ![flamey](public/flamey_avatar.png)Flamey T46: a retro-style robot with a flair for debate, styled in the charming fashion of yesteryear’s technology. His settings? Permanently toggled to ‘teenager mode.’ 10 | 11 | ![starlaxverse](public/starlaxverse_avatar.png)Starlax Verse: a human girl whose heart melts at the slightest hint of cuteness. Guiding these two through the forgotten lore of loops and logic is. 12 | 13 | ![evergreen](public/evergreen_avatar.png)Prof. Evergreen: a scholar as steadfast as his name suggests, yet facing the modern-day plight of filling classroom seats. 14 | 15 | [# Read the book online here](https://www.LostLanguageoftheMachines.com/). 16 | 17 | I am collecting feedback on [Hacker News](https://news.ycombinator.com/item?id=40090580). 18 | 19 | ## Table of Contents 20 | 1. [One and Zero](https://www.LostLanguageoftheMachines.com/chapter1) (Draft Released) 21 | 22 | _Is 'Archaeology Principles: Controlled Silicon of the Past' (APCSP) class as dull as it is rumored? Follow Flamey and Starlaxverse to figure out..._ 23 | 24 | 2. [ASCII](https://www.LostLanguageoftheMachines.com/chapter2) (Draft Released) 25 | 26 | _It turns out, in the very old days, 128 numbers was all it took to create every message and game on computers..._ 27 | 28 | 3. [Color and Image](https://www.LostLanguageoftheMachines.com/chapter3) (Draft Released) 29 | 30 | _I see trees of 00FF00, FF0000 roses too…_ 31 | 32 | 4. Logic Gate (Planned) 33 | 5. Machine Code (Planned) 34 | 6. Assembly (Planned) 35 | 7. ... 36 | 0. [Hello World!](https://www.LostLanguageoftheMachines.com/chapter0) (In Progress) 37 | 38 | _An alternative opening of the story, trying to add a main theme (building a minecraft style game world) to this story_ 39 | 40 | ## Developer Instructions 41 | The book is mostly built with React, Next.js, and Tailwind CSS. 42 | 43 | To run it locally: 44 | ``` 45 | npm install 46 | npm run dev -- -H 0.0.0.0 47 | ``` 48 | 49 | Copyright @2024 Xue Yong Zhi -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lost-language-of-the-machines", 3 | "private": true, 4 | "version": "0.1.0", 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@formkit/drag-and-drop": "^0.3.3", 13 | "@tailwindcss/postcss": "^4.0.3", 14 | "@tanstack/react-query": "^5.66.0", 15 | "@uiw/react-color-block": "^2.3.4", 16 | "framer-motion": "^12.0.6", 17 | "jsonwebtoken": "^9.0.2", 18 | "next": "^15.1.6", 19 | "react": "^19.0.0", 20 | "react-dom": "^19.0.0", 21 | "react-fast-compare": "^3.2.2", 22 | "react-router-dom": "^7.1.5", 23 | "react-scroll-parallax": "^3.4.5", 24 | "react-type-animation": "^3.2.0", 25 | "uuid": "^11.0.5" 26 | }, 27 | "devDependencies": { 28 | "@tanstack/eslint-plugin-query": "^5.66.0", 29 | "@types/jsonwebtoken": "^9.0.8", 30 | "@types/node": "^22", 31 | "@types/react": "^19", 32 | "@types/react-dom": "^19", 33 | "@types/uuid": "^10.0.0", 34 | "autoprefixer": "^10.4.20", 35 | "eslint": "^9", 36 | "eslint-config-next": "15.1.6", 37 | "postcss": "^8.5.1", 38 | "tailwindcss": "^4.0.3", 39 | "typescript": "^5" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | '@tailwindcss/postcss': {}, 5 | autoprefixer: {}, 6 | }, 7 | }; 8 | 9 | export default config; 10 | -------------------------------------------------------------------------------- /public/chapter1/bulb-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter1/bulb-off.png -------------------------------------------------------------------------------- /public/chapter1/bulb-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter1/bulb-on.png -------------------------------------------------------------------------------- /public/chapter1/cat_reaching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter1/cat_reaching.png -------------------------------------------------------------------------------- /public/chapter1/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter1/cover.jpg -------------------------------------------------------------------------------- /public/chapter1/one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter1/one.png -------------------------------------------------------------------------------- /public/chapter1/rule1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter1/rule1.jpg -------------------------------------------------------------------------------- /public/chapter1/rule2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter1/rule2.jpg -------------------------------------------------------------------------------- /public/chapter1/zero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter1/zero.png -------------------------------------------------------------------------------- /public/chapter2/ascii.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter2/ascii.jpg -------------------------------------------------------------------------------- /public/chapter3/mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter3/mario.png -------------------------------------------------------------------------------- /public/chapter3/pixelart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter3/pixelart.jpg -------------------------------------------------------------------------------- /public/chapter3/starwar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/chapter3/starwar.png -------------------------------------------------------------------------------- /public/evergreen_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/evergreen_avatar.png -------------------------------------------------------------------------------- /public/flamey_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/flamey_avatar.png -------------------------------------------------------------------------------- /public/font-sprite.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 12 | 13 | 14 | 17 | 18 | 19 | 22 | 23 | 24 | 27 | 28 | 29 | 32 | 33 | 34 | 37 | 38 | 39 | 42 | 43 | 44 | 47 | 48 | 49 | 52 | 53 | 54 | 57 | 58 | 59 | 62 | 63 | 64 | 67 | 68 | 69 | 72 | 73 | 74 | 77 | 78 | 79 | 82 | 83 | 84 | 87 | 88 | 89 | 92 | 93 | 94 | 97 | 98 | 99 | 102 | 103 | 104 | 107 | 108 | 109 | 112 | 113 | 114 | 117 | 118 | 119 | 122 | 123 | 124 | 127 | 128 | 129 | 132 | 133 | 134 | 137 | 138 | 139 | 142 | 143 | 144 | 147 | 148 | 149 | 152 | 153 | 154 | 157 | 158 | 159 | 162 | 163 | 164 | 167 | 168 | 169 | 172 | 173 | 174 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /public/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 0 5 | -------------------------------------------------------------------------------- /public/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://www.lostlanguageofthemachines.com/chapter1 5 | 2024-05-30 6 | weekly 7 | 1 8 | 9 | 10 | https://www.lostlanguageofthemachines.com/chapter1/chat 11 | 2024-05-30 12 | weekly 13 | 1 14 | 15 | 16 | https://www.lostlanguageofthemachines.com/chapter2 17 | 2024-05-30 18 | weekly 19 | 0.8 20 | 21 | 22 | https://www.lostlanguageofthemachines.com/chapter2/chat 23 | 2024-05-30 24 | weekly 25 | 1 26 | 27 | 28 | https://www.lostlanguageofthemachines.com/chapter3 29 | 2024-05-30 30 | weekly 31 | 0.8 32 | 33 | 34 | https://www.lostlanguageofthemachines.com/chapter3/chat 35 | 2024-05-30 36 | weekly 37 | 0.8 38 | 39 | 40 | https://www.lostlanguageofthemachines.com/chapter4 41 | 2024-05-16 42 | weekly 43 | 0.8 44 | 45 | 46 | -------------------------------------------------------------------------------- /public/starlaxverse_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yong/lost-language-of-the-machines/c6af0195722ae90d0287bb18aef50573b4b89555/public/starlaxverse_avatar.png -------------------------------------------------------------------------------- /src/components/chapter0/Chapter0.tsx: -------------------------------------------------------------------------------- 1 | //Chapter0.tsx 2 | import BounceButton from '../common/BounceButton'; 3 | import renderParagraphs from '../common/renderParagraphs'; 4 | 5 | const storyParts = [ 6 | `“This is interesting” Flamey was impressed by the 200 years old video game in front of him. 7 | 8 | “How do you create a game like that?” Flamey asked, his circuits buzzing with curiosity. 9 | “It’s quite simple,” the young assistant replied proudly. “Just say ‘Hello World!’ and the game world will be created.” 10 | “I mean, how do you create a game from scratch, using computer languages?” Flamey persisted. 11 | The assistant looked puzzled. “Computer languages? You know, everything runs on tokens now. That’s as low-level as it gets.” 12 | “Can you go even lower?” Flamey asked, still unconvinced. 13 | The assistant scratched his head. “Well… I’ve heard there’s a way, but nobody does it anymore. It’s… the lost language of the machines.” 14 | “Where can I learn it?” Flamey’s excitement was palpable. 15 | “You might want to talk to Professor Evergreen,” the assistant suggested. “He’s probably the only one who still understands it. But be careful about it…” He added with a bit of hesitation. “There is rumor that he can make any topic into a long lecture.” 16 | `, 17 | ] 18 | 19 | const Chapter0 = () => { 20 | return ( 21 |
22 |

Chapter 0 "Hello World!"

23 | {renderParagraphs(storyParts[0], 0)} 24 | 25 |
26 | ) 27 | } 28 | 29 | export default Chapter0; -------------------------------------------------------------------------------- /src/components/chapter1/Chapter1.tsx: -------------------------------------------------------------------------------- 1 | //Chapter1.tsx 2 | import Poem from './Poem'; 3 | import Rule1 from './Rule1'; 4 | import Rule2 from './Rule2'; 5 | import Rule3 from './Rule3'; 6 | import BounceButton from '../common/BounceButton'; 7 | import renderParagraphs from '../common/renderParagraphs'; 8 | import FourSwitches from './FourSwitches'; 9 | 10 | const storyParts = [ 11 | `While it was still early in the morning, with fewer flying vehicles leaving traces in the sky, the only thing that disturbed the peaceful silence was Flamey’s footsteps rattling on the dark carbon-titanium floor of the History Hall. A quick glance at his time tracker confirmed his worst fear: there were only two minutes left before the start of the ‘Archaeology Principles: Controlled Silicon of the Past’ class. As he focused on getting there on time, he felt a tug on his arm and turned to see Starlax, his best human friend. 12 | 13 | “Oh, Flamey, I’m so relieved you’re here!” Starlax exclaimed, dragging him along. “Professor Evergreen is known to be a person with ATTITUDE.” 14 | 15 | Flamey groaned. He wouldn’t have signed up for this class if he had not missed the registration deadline for another history course. APCSP was known to be dull and perplexing. Why did he have to learn about the old languages from the Controlled Silicon Era that ancient computers used to speak? The textbook listed a lot of strange names like Binary, Assembly, C, Python, Javascript blah blah. They went extinct 500 years ago! 16 | 17 | They entered the room through a glass bubble door, where Prof. Evergreen was sitting behind his desk with lots of empty chairs. As expected, they were the only two students today. 18 | 19 | “Well,” Prof. Evergreen muttered. “I guess I have to adapt, otherwise this class will not be offered next year. As history has taught us, modern kids have no patience for long lectures. For today’s topic – Binary, how about I start with a poem?”`, 20 | 21 | ///// 22 | 23 | `Flamey and Starlax looked at each other, not sure what to say. With the eager look of their professor waiting for feedback on his “new” style of teaching, Flamey slowly raised his hand and opened up: “Err… I want to know why Binary was invented? Why didn't ancient computers use NORMAL math, like 1,2,3,4,5…?” 24 | 25 | “Convenience, young droid.” Prof. Evergreen elaborated, “Just like the fact that humans having ten fingers contributed to the popularity of the 10 based number system. Ancient computers used electric signals to communicate. So natually 1 represents On, 0 represents Off.” Professor gestured with his hand and a hologram of a cat trying to flip switches showed up. “The switches represent a sequence of Ones and Zeros, which can be used to represent anything, including numbers”.`, 26 | 27 | ///// 28 | 29 | `“Wow.” Starlax was instantly convinced. It was clear that the image of jumping cat had captured her imagination. 30 | “So here is the first rule of a number system”, Prof. Evergreen projected a slide in the air:`, 31 | 32 | ///// 33 | 34 | `“What if a number system’s base is larger than ten? Don’t we run out of digits to use?” Flamey quickly found a way to argue - how can you blame him? As his brain cpu is set to teenage mode, argument is his specialty. 35 | 36 | “You can invent more symbols beyond 0 to 9, or just reuse existing symbols, like letters.” Prof. Evergreen replied as he had heard of this question millions of times. “For example, the 16-based number system (Hex), which is also very popular, uses: A for ten, B for eleven, C for twelve, D for thirteen, E for fourteen and F for fifteen.” 37 | 38 | “Oh…” Flamey was a little disappointed that his question was answered so easily. 39 | 40 | “Once we run out of single symbols – whatever the number is - we are going to combine them to build more complicated numbers. “ Prof. Evergreen continued, “Remember Place Value that you learned at Elementary school? It is the value of each digit in a number based on its position. Here is the second rule of a number system,” Prof. Evergreen casted another slide in the air:`, 41 | 42 | ////// 43 | 44 | ` 45 | 46 | “Oh, it starts to make sense now.” Flamey found something: “So binary actually works the same way as decimal, you count the number of places values then adding them up.” 47 | 48 | “Good find.” Nodded Prof. Evergreen, "That is how you convert a binary number into decimal. 1101 in binary is 1*8+1*4+0*2+1*1, which is 13 in decimal."`, 49 | 50 | ` 51 | “Wow!” said Starlax, not sure she was complimenting the rule or the cats on the slides holding signs. 52 | 53 | ”I'd like to show you more, but we ran out of time. As science has shown, your attention must be depleted now.” Prof. Evergreen walked out of the room in a rush without even acknowledging his two students. 54 | 55 | “Hmm…” Starlax looked at Flamey with a puzzled look, “He is definitely a man with character, but not the way I expected.” 56 | 57 | “Yep.” Answered Flamey, “Don’t think he overused cats to make a point?” 58 | 59 | “Nope”, Said Starlax, “There is no such thing as too many cats.”` 60 | ]; 61 | 62 | const Chapter1 = () => { 63 | return ( 64 |
65 |

Chapter 1 "One and Zero"

66 | {renderParagraphs(storyParts[0], 0)} 67 | 68 | {renderParagraphs(storyParts[1], 1)} 69 | 70 | {renderParagraphs(storyParts[2], 2)} 71 | 72 | {renderParagraphs(storyParts[3], 3)} 73 | 74 | {renderParagraphs(storyParts[4], 4)} 75 | 76 | {renderParagraphs(storyParts[5], 5)} 77 | 78 |
79 | ) 80 | } 81 | 82 | export default Chapter1; 83 | -------------------------------------------------------------------------------- /src/components/chapter1/Cover.jsx: -------------------------------------------------------------------------------- 1 | //Cover.tsx 2 | import React, { useState, useEffect } from 'react'; 3 | import Snowfall from '../../react-snowfall/index.js'; 4 | import { ParallaxBanner } from 'react-scroll-parallax'; 5 | import {motion} from 'framer-motion'; 6 | 7 | const Title = () => { 8 | return ( 9 | 18 |

19 | Lost Language of the Machines 20 |

21 |
22 | ) 23 | } 24 | 25 | const Cover = () => { 26 | const [images, setImages] = useState([]); 27 | 28 | useEffect(() => { 29 | const snowflake1 = new Image(); 30 | snowflake1.src = 'data:image/png;base64,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'; 31 | const snowflake2 = new Image(); 32 | snowflake2.src = 'data:image/png;base64,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'; 33 | setImages([snowflake1, snowflake2]); 34 | }, []); 35 | 36 | return ( 37 | 44 | 45 | 46 | </div> 47 | ), 48 | }, 49 | ]} 50 | style={{ height: '100vh' }} 51 | /> 52 | ); 53 | }; 54 | 55 | export default Cover; 56 | -------------------------------------------------------------------------------- /src/components/chapter1/FourSwitches.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import Image from "next/image"; 3 | 4 | import OnImage from '../../../public/chapter1/bulb-on.png' 5 | import OffImage from '../../../public/chapter1/bulb-off.png' 6 | import CatImage from '../../../public/chapter1/cat_reaching.png' 7 | 8 | interface ScrewProps { 9 | className: string; 10 | } 11 | 12 | const Screw: React.FC<ScrewProps> = ({ className }) => ( 13 | <div 14 | className={`h-2 w-2 rounded-full ${className} bg-[#e3d4a5]`} 15 | style={{ boxShadow: "inset 0 1px 0 rgba(0,0,0,.15)" }} 16 | > 17 | <div 18 | className="h-full w-[1px] mx-auto bg-[rgba(0,0,0,0.2)]" 19 | ></div> 20 | </div> 21 | ); 22 | 23 | interface SwitchProps { 24 | isOn: boolean; 25 | handleSwitch: () => void; 26 | } 27 | 28 | const Switch: React.FC<SwitchProps> = ({ isOn, handleSwitch }) => { 29 | return ( 30 | <div className="flex flex-col items-center justify-center w-1/4 border-t border-black mt-4"> 31 | <Image 32 | src={isOn ? OnImage : OffImage} 33 | alt="Light Bulb" 34 | className="w-1/2 md:w-1/3 lg:w-1/4" 35 | /> 36 | <div 37 | onClick={handleSwitch} 38 | className={"flex flex-col justify-between items-center h-28 w-20 m-auto mt-12 bg-[#fff4d3] rounded-lg shadow-md"} 39 | > 40 | <Screw className="mt-2" /> 41 | <div 42 | className="switch cursor-pointer h-14 w-10 bg-[#fffaea] rounded overflow-hidden flex flex-col justify-between" 43 | style={{ 44 | boxShadow: isOn 45 | ? "0 10px 10px -5px rgba(233,219,176,1), 0 0 0 1px rgba(0,0,0,.1), 0 0 0 4px #fff4d3,0 0 0 5px rgba(0,0,0,.1)" 46 | : "0 10px 10px -5px rgba(233,219,176,0), 0 0 0 1px rgba(0,0,0,.1), 0 0 0 4px #fff4d3,0 0 0 5px rgba(0,0,0,.1)", 47 | }} 48 | > 49 | <div 50 | className={`block h-7 text-center leading-[19px] w-full ${isOn ? "mt-0 bg-[#fff4d3] text-[#64bf60]" : "mt-1 bg-[#fffaea] text-[#bfa371]"}`} 51 | style={{ 52 | boxShadow: isOn ? "none" : "0 -5px 0 #d0b57b", 53 | textShadow: isOn ? "0 0 3px #38ff2e" : "none", 54 | borderRadius: "5px 5px 0 0", 55 | }} 56 | > 57 | ON 58 | </div> 59 | <div 60 | className={`block h-6 text-center leading-[16px] w-full ${isOn ? "mb-1 bg-[#fffaea] text-[#d7bf95]" : "mb-0 bg-[#fff4d3] text-[#a4441a]"}`} 61 | style={{ 62 | boxShadow: isOn ? "0 5px 0 #d0b57b" : "none", 63 | textShadow: isOn ? "0 0 0px transparent" : "0 0 3px #ff4e00", 64 | borderRadius: "0 0 5px 5px", 65 | }} 66 | > 67 | OFF 68 | </div> 69 | </div> 70 | <Screw className="mb-2" /> 71 | </div> 72 | </div> 73 | ); 74 | }; 75 | 76 | const FourSwitches: React.FC = () => { 77 | const [switchStates, setSwitchStates] = useState([true, true, false, true]); 78 | const [isCatJumping, setIsCatJumping] = useState(false); 79 | 80 | const handleSwitch = (index: number) => { 81 | setSwitchStates(switchStates.map((state, i) => i === index ? !state : state)); 82 | setIsCatJumping(true); 83 | }; 84 | 85 | const handleCatClick = () => { 86 | setIsCatJumping(true); 87 | }; 88 | 89 | useEffect(() => { 90 | if (isCatJumping) { 91 | const timer = setTimeout(() => { 92 | setIsCatJumping(false); 93 | }, 500); // adjust the time as needed 94 | 95 | return () => clearTimeout(timer); 96 | } 97 | }, [isCatJumping]); 98 | 99 | return ( 100 | <div className="mb-3 flex flex-col items-center w-full bg-blue-200 border-4 border-dashed border-blue-500 rounded-lg"> 101 | <div className="flex justify-between w-full"> 102 | {switchStates.map((state, index) => ( 103 | <Switch key={index} isOn={state} handleSwitch={() => handleSwitch(index)} /> 104 | ))} 105 | </div> 106 | <div className="grid grid-cols-4 gap-4 w-full pt-12"> 107 | <p className="col-span-3 px-4 pb-4 font-mono"> 108 | <b>Switches Speak Binary!</b> When we look at them, they create a binary code: <b className="text-blue-500">{switchStates.map(state => state ? '1' : '0').join('')}</b>. 109 | Ancient computers use billions of tiny "switches" like these to store information. 110 | </p> 111 | <button onClick={handleCatClick}> 112 | <Image src={CatImage} alt="cat" className={`w-full ${isCatJumping ? 'animate-bounce' : ''}`} /> 113 | </button> 114 | </div> 115 | 116 | </div> 117 | ); 118 | }; 119 | 120 | 121 | export default FourSwitches; 122 | -------------------------------------------------------------------------------- /src/components/chapter1/Legos.tsx: -------------------------------------------------------------------------------- 1 | import { useDragAndDrop } from "@formkit/drag-and-drop/react"; 2 | 3 | const brickStyle = (color: string) => ({ 4 | color: color, 5 | backgroundColor: 'currentColor', 6 | boxShadow: 'inset -1px -1px 0 rgba(0, 0, 0, 0.2), inset 1px 1px 0 rgba(255, 255, 255, 0.2)', 7 | backgroundImage: 'radial-gradient(currentColor 7.5px, transparent 8.5px), radial-gradient(rgba(255, 255, 255, 0.6) 7.5px, transparent 8.5px), radial-gradient(rgba(0, 0, 0, 0.2) 7.5px, transparent 10.5px), radial-gradient(rgba(0, 0, 0, 0.2) 7.5px, transparent 10.5px)', 8 | backgroundSize: '27px 27px', 9 | backgroundPosition: '0px 0px, -0.5px -0.5px, 0px 0px, 3px 3px', 10 | backgroundRepeat: 'repeat' 11 | }); 12 | 13 | const TwoByFour = () => <div className="p-1.5 w-14 h-28" style={brickStyle('#f63')}></div>; 14 | const TwoByTwo = () => <div className="p-1.5 w-14 h-14" style={brickStyle('#43a047')}></div>; 15 | const OneByTwo = () => <div className="p-1.5 w-7 h-14" style={brickStyle('#039be5')}></div>; 16 | const OneByOne = () => <div className="p-1.5 w-7 h-7" style={brickStyle('#757575')}></div>; 17 | 18 | const componentMap = new Map([ 19 | ['TwoByFour', TwoByFour], 20 | ['TwoByTwo', TwoByTwo], 21 | ['OneByTwo', OneByTwo], 22 | ['OneByOne', OneByOne] 23 | ]); 24 | 25 | const Legos = () => { 26 | const [parentRef, items] = useDragAndDrop<HTMLDivElement, string>( 27 | Array.from(componentMap.keys()) 28 | ); 29 | 30 | return ( 31 | <div ref={parentRef} className='flex flex-wrap justify-between filter drop-shadow-2xl p-10'> 32 | {items.map(item => { 33 | const Component = componentMap.get(item); 34 | return Component ? <Component key={item} /> : null; 35 | })} 36 | </div> 37 | ); 38 | } 39 | 40 | export default Legos; 41 | -------------------------------------------------------------------------------- /src/components/chapter1/PlaceValues.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from 'react'; 2 | import { useDragAndDrop } from "@formkit/drag-and-drop/react"; 3 | 4 | interface PlaceValueProps { 5 | cols: number; 6 | rows: number; 7 | depth: number; 8 | } 9 | 10 | const PlaceValue: FC<PlaceValueProps> = ({ cols, rows, depth }) => { 11 | const color = '#BA8C63'; 12 | const borderColor = 'black'; 13 | 14 | return ( 15 | <div style={{ width: `${cols * 10}px`, height: `${rows * 10}px`, perspective: '600px' }}> 16 | <div className="w-full h-full relative" style={{ transformStyle: 'preserve-3d', transform: 'rotateX(-10deg) rotateY(-15deg)', backgroundColor: color }}> 17 | {Array(depth).fill(0).map((_, i) => ( 18 | <div key={i} className="absolute border-black" style={{ width: `${cols * 10}px`, height: `${rows * 10}px`, transform: `translateZ(${i * 10}px)`, backgroundColor: color, borderColor: borderColor, display: 'grid', gridTemplateColumns: `repeat(${cols}, 1fr)`, gridTemplateRows: `repeat(${rows}, 1fr)` }}> 19 | {Array(cols * rows).fill(0).map((_, j) => ( <div key={j} className="border border-black"></div> ))} 20 | </div> 21 | ))} 22 | </div> 23 | </div> 24 | ); 25 | } 26 | 27 | export const ThousandCube: FC = () => <PlaceValue cols={10} rows={10} depth={10} />; 28 | export const HundredBoard: FC = () => <PlaceValue cols={10} rows={10} depth={1} />; 29 | export const TenBead: FC = () => <PlaceValue cols={1} rows={10} depth={1} />; 30 | export const OneUnit: FC = () => <PlaceValue cols={1} rows={1} depth={1} />; 31 | 32 | const componentMap = new Map([ 33 | ['ThousandCube', ThousandCube], 34 | ['HundredBoard', HundredBoard], 35 | ['TenBead', TenBead], 36 | ['OneUnit', OneUnit] 37 | ]); 38 | 39 | const PlaceValues = () => { 40 | const [parentRef, items] = useDragAndDrop<HTMLDivElement, string>( 41 | Array.from(componentMap.keys()) 42 | ); 43 | 44 | return ( 45 | <div ref={parentRef} className='flex flex-wrap justify-between filter drop-shadow-2xl pl-10 pb-10 pt-10'> 46 | {items.map(item => { 47 | const Component = componentMap.get(item); 48 | return Component ? <Component key={item} /> : null; 49 | })} 50 | </div> 51 | ); 52 | } 53 | 54 | export default PlaceValues; 55 | -------------------------------------------------------------------------------- /src/components/chapter1/Poem.tsx: -------------------------------------------------------------------------------- 1 | //Poem.tsx 2 | 3 | const Poem = () => { 4 | return (<p className="mb-3 font-mono text-center bg-gradient-to-r from-blue-200 to-green-200 shadow-lg p-4 rounded-lg"> 5 | Oh, <b>Binary</b>, the language of simplicity, <br/> 6 | With only <b>1</b> and <b>0</b>, you create infinite possibilities. <br/> 7 | From two digits, a power grows <br/> 8 | Of logic, number, art, and code.<br/> 9 | </p>) 10 | } 11 | 12 | export default Poem; -------------------------------------------------------------------------------- /src/components/chapter1/Rule1.tsx: -------------------------------------------------------------------------------- 1 | //Rule1.tsx 2 | import Image from "next/image"; 3 | import Rule1Image from '../../../public/chapter1/rule1.jpg'; 4 | 5 | const Rule1 = () => { 6 | return ( 7 | <div className="mb-3 font-mono text-center bg-blue-200 border-4 border-dashed border-blue-500 p-4 rounded-lg"> 8 | <div className="text-2xl font-bold"> When we say “base-<span className="text-red-600">X</span>”, we’re talking about how many different symbols we use to represent numbers.</div><br /> 9 | <div className="text-base">For example:</div> 10 | <div>In our everyday decimal system (base-<span className="text-red-600">10</span>), we have <span className="text-red-600">ten</span> symbols: <b className="text-blue-500">0,1,2,3,4,5,6,7,8,9</b><br /> 11 | In a binary system (base-<span className="text-red-600">2</span>), we have only <span className="text-red-600">two</span> symbols: <b className="text-blue-500">1</b> and <b className="text-blue-500">0</b>.</div><br /> 12 | <div className="max-w-screen-md mx-auto flex items-center justify-center"> 13 | <Image src={Rule1Image} alt="rule1" /> 14 | </div> 15 | </div> 16 | ) 17 | } 18 | 19 | export default Rule1; 20 | -------------------------------------------------------------------------------- /src/components/chapter1/Rule2.tsx: -------------------------------------------------------------------------------- 1 | //Rule2.tsx 2 | import PlaceValues from "./PlaceValues"; 3 | import Legos from "./Legos"; 4 | 5 | const DecimalExpression = (symbol: number, index:number) => { 6 | return ( 7 | <> 8 | <b className="text-blue-500">{symbol}</b>*<span className="text-red-600">10</span><sup className="text-green-600">{index}</sup> 9 | </> 10 | ) 11 | } 12 | 13 | const BinaryExpression = (symbol: number, index: number) => { 14 | return ( 15 | <> 16 | <b className="text-blue-500">{symbol}</b>*<span className="text-red-600">2</span><sup className="text-green-600">{index}</sup> 17 | </> 18 | ) 19 | } 20 | 21 | const Rule2 = () => { 22 | return ( 23 | <div className="mb-3 font-mono text-center bg-blue-200 border-4 border-dashed border-blue-500 p-4 rounded-lg"> 24 | <div className="text-2xl font-bold">The places values of a base-<span className="text-red-600">X</span> number system always strat from 1 as the rightmost, then the place value will be multipled by <span className="text-red-600">X</span> each time you move left. 25 | </div><br/> 26 | 27 | <div className="text-base">For example:</div> 28 | <div> 29 | In decimal (which is based on <span className="text-red-600">10</span>), we have places like the 30 | <b style={{color: "#BA8C63"}}> ones</b>, 31 | <b style={{color: "#BA8C63"}}>tens</b>, 32 | <b style={{color: "#BA8C63"}}>hundreds</b>, 33 | <b style={{color: "#BA8C63"}}>thousands</b>, and so on. Each place is <span className="text-red-600">10</span> times bigger than the one before it. <br/> 34 | </div> 35 | <PlaceValues/> 36 | <div> 37 | Similarly, In binary (which is based on <span className="text-red-600">2</span>), we have places like the 38 | <b style={{color: "#757575"}}> ones</b>, 39 | <b style={{color: "#039be5"}}>twos</b>, 40 | <b style={{color: "#43a047"}}>fours</b>,and 41 | <b style={{color: "#f63"}}> eights</b>. Each place is 42 | <span className="text-red-600"> 2</span> times bigger than the one before it. 43 | </div> 44 | <Legos/> 45 | </div> 46 | ) 47 | } 48 | 49 | export default Rule2; 50 | -------------------------------------------------------------------------------- /src/components/chapter1/Rule3.tsx: -------------------------------------------------------------------------------- 1 | //Rule2.tsx 2 | import Image from "next/image"; 3 | import Rule2Image from '../../../public/chapter1/rule2.jpg'; 4 | 5 | const Rule3 = () => { 6 | return ( 7 | <div className="mb-3 font-mono text-center bg-blue-200 border-4 border-dashed border-blue-500 p-4 rounded-lg"> 8 | <div className="max-w-screen-md mx-auto flex items-center justify-center"> 9 | <Image src={Rule2Image} alt="rule2" /> 10 | </div> 11 | </div> 12 | ) 13 | } 14 | 15 | export default Rule3; 16 | -------------------------------------------------------------------------------- /src/components/chapter1/Switch.tsx: -------------------------------------------------------------------------------- 1 | //Switch.tsx 2 | import Image from 'next/image'; 3 | import CatImage from '../../../public/chapter1/cat.png' 4 | 5 | const Switch = () => { 6 | return ( 7 | <div className="mb-3 text-center bg-blue-200 border-4 border-dashed border-blue-500 p-4 rounded-lg"> 8 | <div className="max-w-screen-md mx-auto flex items-center justify-center"> 9 | <Image src={CatImage} alt="Cat" /> 10 | </div> 11 | </div> 12 | ) 13 | } 14 | 15 | export default Switch; -------------------------------------------------------------------------------- /src/components/chapter2/Answer.tsx: -------------------------------------------------------------------------------- 1 | //Answer.tsx 2 | 3 | const Answer = () => { 4 | return (<p className="mb-3 font-mono text-center bg-gradient-to-r from-blue-200 to-green-200 shadow-lg p-4 rounded-lg"> 5 | There are 10 types of people in the world: those who understand binary, and those who don't. 6 | 7 | </p>) 8 | } 9 | 10 | export default Answer; -------------------------------------------------------------------------------- /src/components/chapter2/AsciiTable.tsx: -------------------------------------------------------------------------------- 1 | //AsciiTable.tsx 2 | import React from 'react'; 3 | 4 | const AsciiTable = () => { 5 | const asciiChars = Array.from({length: 95}, (_, i) => String.fromCharCode(i + 32)); 6 | const quarter = Math.ceil(asciiChars.length / 4); 7 | const firstQuarter = asciiChars.slice(0, quarter); 8 | const secondQuarter = asciiChars.slice(quarter, quarter * 2); 9 | const thirdQuarter = asciiChars.slice(quarter * 2, quarter * 3); 10 | const fourthQuarter = asciiChars.slice(quarter * 3); 11 | 12 | const renderTable = (chars: string[], start: number) => ( 13 | <table className="w-full text-center divide-y divide-gray-200"> 14 | <thead> 15 | <tr> 16 | <th className="px-1 py-1 text-xs font-medium text-gray-500 uppercase tracking-wider">Dec</th> 17 | <th className="px-1 py-1 text-xs font-medium text-gray-500 uppercase tracking-wider">Hex</th> 18 | <th className="px-1 py-1 text-xs font-medium text-gray-500 uppercase tracking-wider">Chr</th> 19 | </tr> 20 | </thead> 21 | <tbody className="divide-y divide-gray-200"> 22 | {chars.map((char, index) => ( 23 | <tr key={index}> 24 | <td className="px-1 py-1 whitespace-nowrap">{start + index}</td> 25 | <td className="px-1 py-1 whitespace-nowrap">{(start + index).toString(16).toUpperCase()}</td> 26 | <td className="px-1 py-1 whitespace-nowrap font-bold">{char === ' ' ? 'SPACE' : char}</td> 27 | </tr> 28 | ))} 29 | </tbody> 30 | </table> 31 | ); 32 | 33 | return ( 34 | <div className="flex flex-col items-center justify-center mb-3 bg-blue-200 border-4 border-dashed border-blue-500 p-4 rounded-lg"> 35 | <h1 className="text-2xl font-bold mb-4">Partial ASCII Table</h1> 36 | <div className="overflow-auto grid grid-cols-2 md:grid-cols-4 lg:grid-cols-4"> 37 | <div>{renderTable(firstQuarter, 32)}</div> 38 | <div>{renderTable(secondQuarter, 32 + quarter)}</div> 39 | <div>{renderTable(thirdQuarter, 32 + quarter * 2)}</div> 40 | <div>{renderTable(fourthQuarter, 32 + quarter * 3)}</div> 41 | </div> 42 | </div> 43 | ); 44 | }; 45 | 46 | export default AsciiTable; 47 | -------------------------------------------------------------------------------- /src/components/chapter2/Chapter2.tsx: -------------------------------------------------------------------------------- 1 | //Chapter2.tsx 2 | import BounceButton from '../common/BounceButton' 3 | import Code from './Code' 4 | import Hex from './Hex' 5 | import Answer from './Answer' 6 | import AsciiTable from './AsciiTable' 7 | import renderParagraphs from '../common/renderParagraphs' 8 | 9 | const storyParts = [ 10 | `Despite a recent brush with overheating, Flamey spotted his friend Starlax enthusiastically waving from the iconic blue steps of Literature Hall. "Flamey! Creative Writing too?" 11 | 12 | "Indeed," Flamey replied, still climbing the stairs. "Running late again?" 13 | 14 | "Not at all," Starlax smiled. "But Mrs. Katseen's class is popular. Early arrival secures better seats." 15 | 16 | "True," Flamey agreed, recalling the lottery system implemented due to high demand. Entering the classroom, they were surprised to find Professor Evergreen behind a transparent carbon fiber desk, surrounded by empty chairs. 17 | 18 | "Apologies," Flamey started, unsure if they were in the right room. 19 | 20 | "This is Creative Writing," Professor Evergreen confirmed. "Sadly, a hybrid virus is sweeping the campus, striking many students and staff, including Mrs. Katseen. That’s why I’m here today as your substitute." 21 | 22 | Flamey and Starlax exchanged nervous glances. This wasn't exactly their planned adventure. 23 | 24 | "According to Mrs. Katseen's notes," Professor Evergreen continued, "we're to discuss 'Aegis: Saga of Conflict, Idealism, and Identity' a masterpiece penned by Edward Grant during the Third Human Robot War..." 25 | He paused. "You're familiar with it, I presume?" 26 | 27 | "Yes," Starlax replied. "Often called ASCII, this text laid the foundation for our harmonious coexistence." 28 | 29 | "And I've done five book reports on it since kindergarten," Flamey added proudly. 30 | 31 | "ASCII, intriguing," Professor Evergreen murmured. "There's also an ancient text encoding method called ASCII, standing for American Standard Code for Information Interchange. Remember I mentioned binary representing anything? Have you considered how text can be encoded?" 32 | 33 | "No," Flamey confessed. "I thought binary was just for numbers." 34 | 35 | "Precisely," Professor Evergreen said. "Since languages have finite letters and symbols, we can assign numbers to them. ASCII assigns 0-127 to represent English letters, both upper and lower case, along with special characters." Then he casted a chart in the air that showed the mapping.`, 36 | ////////////////// 37 | 38 | `Literature analysis is not my area of expertise," he admitted, "and I would not want to give you a suboptimal experience. How about you two decipher a message using this ASCII together, then conclude our session?" 39 | 40 | "Sure," Flamey and Starlax agreed eagerly. `, 41 | 42 | ///////////////// 43 | `"Before we do that, I have to teach you another thing," Professor Evergreen projected a slide. "Binary numbers can be lengthy, so we'll use hexadecimal, or hex, which is base 16. It uses 0-9 for values zero to nine, and A-F for ten to fifteen." 44 | 45 | “What? When people discuss binary, they’re actually referring to hex?” Flamey’s instinct was to declare this as ‘cheating,’ but he halted mid-thought. Urgency tugged at him; he yearned to unravel the puzzle and slip out of class a little earlier. 46 | 47 | "Yes, it happens a lot", Prof Evergrenn nodded. He then presented the code:`, 48 | 49 | ///////////////// 50 | `“So 54 is ‘T’, 68 is ‘h’, 65 is ‘e’....” The two friends started to translate. "And 20 is a whitespace..." 51 | 52 | And the message slowly revealed itself: `, 53 | 54 | //////////////// 55 | 56 | `“Wait a sec…”, Flamey was puzzled, “The math does not seem right, where are the other 8 types?” 57 | 58 | “Oh, Flamey….” Starlax giggled, “You are the one who doesn't understand binary”. 59 | 60 | A beat of silence followed. Then, Flamey's metallic form vibrated with laughter. "This binary joke got me."` 61 | ]; 62 | 63 | const Chapter2 = () => { 64 | return ( 65 | <article className="text-wrap p-6 md:p-12 lg:p-24 lg:ml-36 lg:mr-36"> 66 | <h1 className="text-center text-2xl font-bold mb-4">Chapter 2 "ASCII"</h1> 67 | {renderParagraphs(storyParts[0], 0)} 68 | <AsciiTable/> 69 | {renderParagraphs(storyParts[1], 1)} 70 | <Hex/> 71 | {renderParagraphs(storyParts[2], 2)} 72 | <Code/> 73 | {renderParagraphs(storyParts[3], 3)} 74 | <Answer/> 75 | {renderParagraphs(storyParts[4], 4)} 76 | <BounceButton url='chapter2/chat'/> 77 | </article> 78 | ) 79 | } 80 | 81 | export default Chapter2; 82 | -------------------------------------------------------------------------------- /src/components/chapter2/Code.tsx: -------------------------------------------------------------------------------- 1 | //Code.tsx 2 | 3 | const Code = () => { 4 | return (<p className="mb-3 font-mono text-center bg-gradient-to-r from-blue-200 to-green-200 shadow-lg p-4 rounded-lg uppercase"> 5 | 54 68 65 72 65 20 61 72 65 20 31 30 20 74 79 70 65 73 20 6f 66 20 70 65 6f 70 6c 65 20 69 6e 20 74 68 65 20 77 6f 72 6c 64 3a 0a 20 20 74 68 6f 73 65 20 77 68 6f 20 75 6e 64 65 72 73 74 61 6e 64 20 62 69 6e 61 72 79 2c 0a 20 20 61 6e 64 20 74 68 6f 73 65 20 77 68 6f 20 64 6f 6e 27 74 2e 6 | </p>) 7 | } 8 | 9 | export default Code; -------------------------------------------------------------------------------- /src/components/chapter2/Hex.tsx: -------------------------------------------------------------------------------- 1 | //Hex.tsx 2 | import React from 'react'; 3 | 4 | const Hex = () => { 5 | const mapping = [ 6 | { binary: '0000', hex: '0' }, 7 | { binary: '0001', hex: '1' }, 8 | { binary: '0010', hex: '2' }, 9 | { binary: '0011', hex: '3' }, 10 | { binary: '0100', hex: '4' }, 11 | { binary: '0101', hex: '5' }, 12 | { binary: '0110', hex: '6' }, 13 | { binary: '0111', hex: '7' }, 14 | { binary: '1000', hex: '8' }, 15 | { binary: '1001', hex: '9' }, 16 | { binary: '1010', hex: 'A' }, 17 | { binary: '1011', hex: 'B' }, 18 | { binary: '1100', hex: 'C' }, 19 | { binary: '1101', hex: 'D' }, 20 | { binary: '1110', hex: 'E' }, 21 | { binary: '1111', hex: 'F' }, 22 | ]; 23 | 24 | return ( 25 | <div className="mb-3 text-center bg-blue-200 border-4 border-dashed border-blue-500 p-4 rounded-lg"> 26 | <div className="text-2xl font-bold"><span className='text-blue-500'>HEX</span> - human friendly ‘<span className='text-green-700'>binary</span>’</div><br/> 27 | Since <span className='text-blue-500'>16</span> is a multiple of <span className='text-green-700'>2</span> (2<sup>4</sup>), it is very easy to convert <span className='text-green-700'>binary</span> to <span className='text-blue-500'>hex</span> and back.<br/> 28 | 29 | <b>Step 1</b>: Just divide the <span className='text-green-700'>binary</span> number into groups of 4 digits, starting from the rightmost digit. You can add leading zeros if the number of digits isn't evenly divisible by 4.<br/> 30 | <b>Step 2</b>: Convert each group of 4 <span className='text-green-700'>binary</span> digits to its corresponding <span className='text-blue-500'>hexadecimal</span> digit using the following mapping:<br/> 31 | 32 | <div className="grid grid-cols-4 lg:grid-cols-8 gap-4 mx-auto"> 33 | {mapping.map((item, index) => ( 34 | <div key={index}><span className='text-green-700'>{item.binary}</span>=<b className='text-blue-500'>{item.hex}</b></div> 35 | ))} 36 | </div> 37 | <br/> 38 | <b>For example</b>: <span className='text-green-700'>00000000</span> becomes <b className='text-blue-500'>00</b>, 39 | <span className='text-green-700'>11111111</span> becomes <b className='text-blue-500'>FF</b> - much easier to read and write! 40 | </div> 41 | ) 42 | } 43 | 44 | export default Hex; 45 | -------------------------------------------------------------------------------- /src/components/chapter3/Chapter3.tsx: -------------------------------------------------------------------------------- 1 | //Chapter3.tsx 2 | import Image from 'next/image'; 3 | import BounceButton from '../common/BounceButton' 4 | import renderParagraphs from '../common/renderParagraphs'; 5 | import RGB from './RGB'; 6 | import RGB2 from './RGB2'; 7 | 8 | import StarWarImage from '../../../public/chapter3/starwar.png'; 9 | import MarioImage from '../../../public/chapter3/mario.png'; 10 | 11 | const storyParts = [ 12 | `Fall is always Flamey’s favorite season. The trees of green and skies of blue always put his mind at ease. On his way to the Art Studio, his mind was filled with thoughts about the art project he was going to do that day. 13 | 14 | “Hi Flamey!” A familiar, cheerful voice came from behind. His friend, Starlax, approached him quickly on her jetpack. “Are we in the same class again?” 15 | “Apparently,” Flamey said. “Art is my favorite subject.” 16 | The two friends entered the studio together. It was still early, and the room was quite empty - except for Prof. Evergreen, who was sitting behind a painting and working on something. 17 | “Oops,” Flamey exchanged a quick look with Starlax, calculating the possibility of having Evergreen as a substitute for their art teacher. 18 | “Oh, you two,” Prof. Evergreen noticed them. “Did you get the notice that the art class has been moved to 3pm? I am borrowing this room to finish a piece of art of mine before the class starts.” 19 | “No,” Flamey and Starlax shook their heads. Apparently, the notification system on the campus had malfunctioned again. Now they had one extra hour in the studio. 20 | Starlax pulled out her screenbook and started to do some sketching. Meanwhile, Flamey’s attention was drawn to a fighting scene that Prof. Evergreen was drawing. 21 | “What are they fighting with?” Flamey couldn’t hold back his curiosity any longer. 22 | “Oh, that is a scene from an old movie named Star Wars. They are fighting with Lightsabers, a sword-like weapon made of lasers,” Prof. Evergreen answered. “It is a fascinating idea, but scientists nowadays still can’t find a way to make light stop mid-air,” he added.`, 23 | 24 | /////// 25 | 26 | `“Cool,” Flamey was more interested now. He quickly loaded movie-related information into his knowledge unit. “So the guy with the red one is the bad guy, and the good guy has the green lightsaber. When the two lightsabers cross, it becomes yellow – that makes sense, just like when we mix red paint with green paint, it becomes yellow paint.” 27 | “Good find,” nodded Prof. Evergreen, “Do you know how color is encoded in binary?” 28 | “Err…Just assign a number? I guess we do not have infinite colors, so that should work,” Flamey answered. He kind of regretted turning the conversation into a teaching moment. 29 | “Right,” Prof. Evergreen paused his work and became eloquent. “Let’s start with one color, red. There are actually lots of different reds, light red, dark red, you can think of it as light, and we can assign 256 levels of brightness to it, which is 00 to FF in Hex, with FF being the brightest.” He showed a slide in the air:`, 30 | 31 | ////// 32 | 33 | `“You can do more or less, but 256 levels are good enough in real life,” he added. “With those three primary colors assigned to a number, you can mix them to get any other colors, just like you can do with real paints.” Prof. Evergreen moved on. “One common way is called RGB (red, green, and blue) encoding, as in put the previous numbers in red, green, blue order, for example.” He cast another slide in the air:`, 34 | 35 | ////// 36 | 37 | `“How do you encode a whole picture?” Starlax stopped her work and joined the conversation. 38 | "There are lots of ways to do that,” Prof. Evergreen replied. But he paused as lots of other students started to enter the studio. “It seems I have to exit now. I will leave this picture as a clue. I am sure you can figure it out.”` 39 | 40 | ]; 41 | 42 | const Chapter3 = () => { 43 | return ( 44 | <article className="text-wrap p-6 md:p-12 lg:p-24 lg:ml-36 lg:mr-36"> 45 | <h1 className="text-center text-2xl font-bold mb-4">Chapter 3 "Color and Image"</h1> 46 | 47 | {renderParagraphs(storyParts[0], 0)} 48 | 49 | <div className="mb-3 font-mono text-center bg-blue-200 border-4 border-dashed border-blue-500 p-4 rounded-lg"> 50 | <div className="max-w-screen-md mx-auto flex items-center justify-center"> 51 | <Image src={StarWarImage} alt="starwar" /> 52 | </div> 53 | </div> 54 | 55 | {renderParagraphs(storyParts[1], 1)} 56 | 57 | <RGB/> 58 | 59 | {renderParagraphs(storyParts[2], 2)} 60 | 61 | <RGB2/> 62 | 63 | {renderParagraphs(storyParts[3], 3)} 64 | 65 | <div className="mb-3 font-mono text-center bg-blue-200 border-4 border-dashed border-blue-500 p-4 rounded-lg"> 66 | <div className="max-w-screen-md mx-auto flex items-center justify-center"> 67 | <Image src={MarioImage} alt="mario" /> 68 | </div> 69 | </div> 70 | 71 | <BounceButton url='chapter3/chat'/> 72 | 73 | </article> 74 | ) 75 | } 76 | 77 | 78 | export default Chapter3; -------------------------------------------------------------------------------- /src/components/chapter3/RGB.tsx: -------------------------------------------------------------------------------- 1 | //RGB.tsx 2 | 3 | import React, { FC } from 'react'; 4 | 5 | interface ColorBarProps { 6 | color: string; 7 | label: string; 8 | } 9 | 10 | const ColorBar: FC<ColorBarProps> = ({ color, label }) => ( 11 | <div className="flex items-center space-x-2 mb-4"> 12 | <div>{label}</div> 13 | <div className="w-full h-6 bg-gradient-to-r relative" style={{ backgroundImage: `linear-gradient(to right, #000, ${color})` }}> 14 | <div className="absolute left-0 bottom-0 text-white">00</div> 15 | <div className="absolute right-0 bottom-0 text-white">FF</div> 16 | </div> 17 | </div> 18 | ); 19 | 20 | const RGB: FC = () => { 21 | return ( 22 | <div className="mb-3 font-mono text-center bg-blue-200 border-4 border-dashed border-blue-500 p-4 rounded-lg"> 23 | <ColorBar color="#FF0000" label="R" /> 24 | <ColorBar color="#00FF00" label="G" /> 25 | <ColorBar color="#0000FF" label="B" /> 26 | </div> 27 | ) 28 | } 29 | 30 | export default RGB; 31 | 32 | -------------------------------------------------------------------------------- /src/components/chapter3/RGB2.tsx: -------------------------------------------------------------------------------- 1 | //RGB2.tsx 2 | import React, { useState } from 'react'; 3 | import Block from '@uiw/react-color-block'; 4 | 5 | function ColorPicker() { 6 | const [hex, setHex] = useState("#800080"); 7 | return ( 8 | <Block 9 | color={hex} 10 | onChange={(color) => setHex(color.hex)} 11 | /> 12 | ); 13 | } 14 | 15 | const RGB2 = () => { 16 | return ( 17 | <div className="mb-3 font-mono bg-blue-200 border-4 border-dashed border-blue-500 p-4 rounded-lg"> 18 | <b className="text-red-600">00</b><b className="text-green-600">00</b><b className="text-blue-600">00</b> 19 | <i className="fa-solid fa-cloud" style={{ color: '#000000' }}></i> 20 | : No red light, no green light, and no blue light. It is complete darkness (black). <br/> 21 | 22 | <b className="text-red-600">FF</b><b className="text-green-600">00</b><b className="text-blue-600">00</b> 23 | <i className="fa-solid fa-apple-whole" style={{ color: '#FF0000' }}></i> 24 | : Full brightness red, and nothing else. It is just as red as it can be. <br/> 25 | 26 | <b className="text-red-600">00</b><b className="text-green-600">80</b><b className="text-blue-600">00</b> 27 | <i className="fa-solid fa-tree" style={{ color: '#008000' }}></i> 28 | : Half brightness of green, and nothing else. I see tree of greens... <br/> 29 | 30 | <b className="text-red-600">FF</b><b className="text-green-600">FF</b><b className="text-blue-600">FF</b> 31 | <i className="fa-solid fa-lightbulb" style={{ color: '#FFFFFF' }}></i> 32 | : Full brightness red, full brightness green, and full brightness blue. It is just white, just as Isaac Newton discovered that clear white light was composed of visible colors. <br/> 33 | 34 | <b className="text-red-600">FF</b><b className="text-green-600">FF</b><b className="text-blue-600">00</b> 35 | <i className="fa-solid fa-lemon" style={{ color: '#FFFF00' }}></i> 36 | : Full red, full green, and no blue. This mix creates yellow. By lowering the brightness of red and green, you can get a different yellow. 37 | 38 | <br/> 39 | <div className='flex justify-center mt-4'> 40 | <ColorPicker/> 41 | </div> 42 | </div> 43 | ) 44 | } 45 | 46 | export default RGB2; 47 | -------------------------------------------------------------------------------- /src/components/common/BounceButton.tsx: -------------------------------------------------------------------------------- 1 | import { TypeAnimation } from 'react-type-animation' 2 | import {UrlProps} from '../common/types' 3 | 4 | const BounceButton: React.FC<UrlProps> = ({url}) => { 5 | return ( 6 | <div className="flex flex-col items-center justify-center mt-8"> 7 | <LaterTonight/> 8 | <a href={url} className="animate-bounce bg-white dark:bg-slate-800 p-2 w-10 h-10 ring-1 ring-slate-900/5 dark:ring-slate-200/20 shadow-lg rounded-full"> 9 | <svg className="w-6 h-6 text-violet-500" fill="none" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" viewBox="0 0 24 24" stroke="currentColor"> 10 | <path d="M19 14l-7 7m0 0l-7-7m7 7V3"></path> 11 | </svg> 12 | </a> 13 | </div> 14 | ) 15 | } 16 | 17 | const LaterTonight = () => { 18 | return ( 19 | <TypeAnimation 20 | sequence={[ 21 | // Same substring at the start will only be typed out once, initially 22 | 'Later tonight...', 23 | 1000, // wait 1s 24 | 'In the dormitory...', 25 | 1000 26 | ]} 27 | className="text-2xl font-bold mb-4" 28 | wrapper="span" 29 | speed={50} 30 | 31 | repeat={Infinity} 32 | /> 33 | ); 34 | }; 35 | 36 | export default BounceButton; -------------------------------------------------------------------------------- /src/components/common/NextButton.tsx: -------------------------------------------------------------------------------- 1 | //NextButton.jsx 2 | 3 | import {UrlProps} from '../common/types' 4 | 5 | const NextButton: React.FC<UrlProps> = ({ url }) => { 6 | return ( 7 | <div className="flex items-center justify-center"> 8 | <a href={url} className="mt-4 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded inline-block"> 9 | Next Chapter → 10 | </a> 11 | </div> 12 | ) 13 | } 14 | 15 | export default NextButton; 16 | -------------------------------------------------------------------------------- /src/components/common/renderParagraphs.tsx: -------------------------------------------------------------------------------- 1 | const renderParagraphs = (storyPart: string, i: number) => { 2 | return storyPart.split('\n').map((paragraph, j) => { 3 | const className = j === 0 && i === 0 ? "mb-3 first-letter:text-7xl first-letter:font-bold first-letter:me-3 first-letter:float-start" : "mb-3"; 4 | return <p key={i*100 + j} className={className}>{paragraph}</p> 5 | }); 6 | }; 7 | 8 | export default renderParagraphs; -------------------------------------------------------------------------------- /src/components/common/transition.css: -------------------------------------------------------------------------------- 1 | .slide-in { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | width: 100%; 6 | height: 100vh; 7 | background: #0f0f0f; 8 | transform-origin: bottom; 9 | } 10 | 11 | .slide-out { 12 | position: fixed; 13 | top: 0; 14 | left: 0; 15 | width: 100%; 16 | height: 100vh; 17 | background: #0f0f0f; 18 | transform-origin: top; 19 | } -------------------------------------------------------------------------------- /src/components/common/transition.jsx: -------------------------------------------------------------------------------- 1 | /*import {motion} from 'framer-motion'; 2 | import "./transition.css"; 3 | 4 | const Transition = (OgComponent) => { 5 | return () => ( 6 | <> 7 | <OgComponent /> 8 | <motion.div 9 | className='slide-in' 10 | initial={{scaleX: 0}} 11 | animate={{scaleY: 0}} 12 | exit={{scaleY: 1}} 13 | transition={{duration: 1, ease: [0.22, 1, 0.36, 1]}} 14 | /> 15 | <motion.div 16 | className='slide-out' 17 | initial={{scaleX: 1}} 18 | animate={{scaleY: 0}} 19 | exit={{scaleY: 0}} 20 | transition={{duration: 1, ease: [0.22, 1, 0.36, 1]}} 21 | /> 22 | </> 23 | ) 24 | } 25 | 26 | export default Transition;*/ -------------------------------------------------------------------------------- /src/components/common/types.ts: -------------------------------------------------------------------------------- 1 | export interface UrlProps { 2 | url: string; 3 | } -------------------------------------------------------------------------------- /src/components/common/withCover.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ParallaxProvider, ParallaxBanner } from 'react-scroll-parallax'; // Import the necessary components 3 | 4 | // Define the higher-order component (HOC) 5 | const withParallax = (WrappedComponent, imageSrc) => { 6 | return class WithParallax extends React.Component { 7 | render() { 8 | return ( 9 | <ParallaxProvider> 10 | <ParallaxBanner 11 | layers={[ 12 | { image: imageSrc }, // Use the provided image source 13 | { 14 | speed: -20, 15 | children: ( 16 | <div className="absolute inset-0 flex items-center justify-center"> 17 | <h1 className="backdrop-blur-sm text-center font-bold text-black z-50 text-3xl sm:text-4xl md:text-5xl lg:text-6xl xl:text-7xl 2xl:text-8xl"> 18 | Lost Language of the Machines 19 | </h1> 20 | </div> 21 | ), 22 | }, 23 | ]} 24 | style={{ height: '100vh' }} 25 | /> 26 | <WrappedComponent {...this.props} /> 27 | </ParallaxProvider> 28 | ); 29 | } 30 | }; 31 | }; 32 | 33 | export default withParallax; // Export the HOC 34 | -------------------------------------------------------------------------------- /src/components/demo/AnimatedFIFOList.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { motion, AnimatePresence } from 'framer-motion'; 3 | 4 | const AnimatedFIFOList = () => { 5 | const [list, setList] = useState(Array(8).fill(0)); 6 | 7 | const handleClick = (value) => { 8 | setList((prevList) => { 9 | const newList = [...prevList]; 10 | newList.shift(); 11 | newList.push(value); 12 | return newList; 13 | }); 14 | }; 15 | 16 | return ( 17 | <div className="flex flex-col items-center"> 18 | <button 19 | className="p-2 m-2 bg-blue-500 text-white" 20 | onClick={() => handleClick(1)} 21 | > 22 | Add 1 23 | </button> 24 | <button 25 | className="p-2 m-2 bg-blue-500 text-white" 26 | onClick={() => handleClick(0)} 27 | > 28 | Add 0 29 | </button> 30 | <div className="flex space-x-2"> 31 | <AnimatePresence> 32 | {list.map((item, index) => ( 33 | <motion.div 34 | key={index} 35 | initial={{ opacity: 0, x: -50 }} 36 | animate={{ opacity: 1, x: 0 }} 37 | exit={{ opacity: 0, x: 50 }} 38 | className="p-2 bg-green-500 text-white" 39 | > 40 | {item} 41 | </motion.div> 42 | ))} 43 | </AnimatePresence> 44 | </div> 45 | </div> 46 | ); 47 | }; 48 | 49 | export default AnimatedFIFOList; 50 | -------------------------------------------------------------------------------- /src/components/demo/Bmp.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | 3 | function rgbToHex(color) { 4 | // Remove the # from the start of the color 5 | color = color.slice(1); 6 | 7 | // Convert the color to a number 8 | const num = parseInt(color, 16); 9 | 10 | // Extract the RGB values 11 | const r = num >> 16; 12 | const g = (num >> 8) & 255; 13 | const b = num & 255; 14 | 15 | // Convert the RGB values to a BMP hex color 16 | return ((b << 16) | (g << 8) | r).toString(16).padStart(6, '0'); 17 | } 18 | 19 | function buildBmpHexCode(grid) { 20 | // Reverse the grid so the first row becomes the last 21 | const reversedGrid = [...grid].reverse(); 22 | 23 | // BMP file header 24 | const header = [ 25 | { text: '424d', color: '#000000', backgroundColor: '#b184eb', label: 'BM' }, 26 | { text: '46020000', color: '#000000', label: 'file size (70,000 bytes)' }, 27 | { text: '00000000', color: '#000000', label: 'reserved' }, 28 | { text: '36000000', color: '#000000', label: 'offset to pixel data' } 29 | ]; 30 | 31 | // DIB header 32 | const dibHeader = [ 33 | { text: '28000000', color: '#000000', label: 'DIB header size' }, 34 | { text: '10000000', color: '#000000', backgroundColor: '#b184eb', label: 'width (16 pixels)' }, 35 | { text: '10000000', color: '#000000', backgroundColor: '#b184eb', label: 'height (16 pixels)' }, 36 | { text: '0100', color: '#000000', label: 'color planes' }, 37 | { text: '1800', color: '#000000', label: 'bits per pixel' }, 38 | { text: '00000000', color: '#000000', label: 'compression method' }, 39 | { text: '10020000', color: '#000000', label: 'image size (69,632 bytes)' }, 40 | { text: '130b0000', color: '#000000', label: 'horizontal resolution' }, 41 | { text: '130b0000', color: '#000000', label: 'vertical resolution' }, 42 | { text: '00000000', color: '#000000', label: 'color palette' }, 43 | { text: '00000000', color: '#000000', label: 'important colors' } 44 | ]; 45 | 46 | // Pixel data 47 | let pixelData = [[]]; 48 | for (let y = 0; y < 16; y++) { 49 | for (let x = 0; x < 16; x++) { 50 | const color = reversedGrid[y][x]; 51 | if (typeof color !== 'string' || !/^#[0-9a-f]{6}$/i.test(color)) { 52 | return [[]]; 53 | } 54 | pixelData[pixelData.length - 1].push({ text: rgbToHex(color), color }); 55 | } 56 | pixelData.push([]); // New row after each row 57 | } 58 | 59 | return [header, dibHeader, ...pixelData]; 60 | } 61 | 62 | // New component to display hex code with color 63 | function HexCode({ code, color, backgroundColor='white'}) { 64 | return <span style={{ color, backgroundColor }} className="font-mono text-sm">{code}</span>; 65 | } 66 | 67 | function ColorPicker({selectedColor, onColorClick }) { 68 | const colors = ['#000000', '#FFFFFF', '#FF0000', '#00FF00', '#FFFF00', '#0000FF', '#FFA500', '#800080', '#FFC0CB']; 69 | return ( 70 | <div className="flex mb-5"> 71 | {colors.map((color, i) => ( 72 | <div 73 | key={i} 74 | onClick={() => onColorClick(color)} 75 | style={{ 76 | backgroundColor: color, 77 | border: selectedColor === color ? '2px solid #000' : '1px solid #000' 78 | }} 79 | className="w-5 h-5" 80 | > 81 | {selectedColor === color && <span className="text-white">✔️</span>} 82 | </div> 83 | ))} 84 | </div> 85 | ); 86 | } 87 | 88 | function Bmp() { 89 | 90 | const [grid, setGrid] = useState(Array(16).fill().map(() => Array(16).fill('#FFFFFF'))); 91 | const [selectedColor, setSelectedColor] = useState('#FFFF00'); 92 | 93 | const handleCellClick = (x, y) => { 94 | const newGrid = grid.slice(); 95 | newGrid[y][x] = selectedColor; 96 | setGrid(newGrid); 97 | }; 98 | 99 | const handleColorClick = (color) => { 100 | setSelectedColor(color); 101 | }; 102 | 103 | // Convert grid to BMP hex code 104 | const hexCode = buildBmpHexCode(grid); 105 | const bmpHexCode = hexCode.map((row, i) => ( 106 | <div key={i} className="flex"> 107 | {row.map((code, j) => ( 108 | <HexCode key={j} code={code.text} backgroundColor={code.backgroundColor} color={code.color === '#FFFFFF' ? 'gray-300' : code.color} /> 109 | ))} 110 | </div> 111 | )); 112 | 113 | // Convert hex code to Blob and create object URL 114 | const hexString = hexCode.flat().map(code => code.text).join(''); 115 | const byteArray = new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); 116 | const blob = new Blob([byteArray], { type: 'image/bmp' }); 117 | const url = URL.createObjectURL(blob); 118 | 119 | // Clean up object URL 120 | useEffect(() => { 121 | return () => URL.revokeObjectURL(url); 122 | }, [url]); 123 | 124 | return ( 125 | <div className="flex flex-col items-center"> 126 | <h1 className="text-2xl font-bold">BMP Image Creator</h1> 127 | <p className="mb-4">Select a color and click on the grid to paint. The grid represents a 16x16 BMP image.</p> 128 | <ColorPicker selectedColor={selectedColor} onColorClick={setSelectedColor} /> 129 | 130 | <a href={url} download="image.bmp" className="mb-5">Download BMP</a> {/* Download link */} 131 | <div className="flex flex-col md:flex-row justify-between w-full md:w-4/5"> 132 | <div className="flex flex-wrap"> 133 | {grid.map((row, y) => ( 134 | <div key={y} className="flex"> 135 | {row.map((color, x) => ( 136 | <div 137 | key={`${x}-${y}`} 138 | onClick={() => handleCellClick(x, y)} 139 | style={{ backgroundColor: color }} 140 | className="w-5 h-5 border border-black" 141 | /> 142 | ))} 143 | </div> 144 | ))} 145 | </div> 146 | <div className="flex flex-col">{bmpHexCode}</div> {/* Display hex code in rows */} 147 | </div> 148 | </div> 149 | ); 150 | } 151 | 152 | export default Bmp; 153 | -------------------------------------------------------------------------------- /src/components/demo/ClockFont.tsx: -------------------------------------------------------------------------------- 1 | // ClockCharacter.tsx 2 | import React from 'react'; 3 | 4 | interface ClockCharacterProps { 5 | char: string; 6 | } 7 | 8 | const ClockCharacter: React.FC<ClockCharacterProps> = ({ char }) => { 9 | return ( 10 | <div className="block aspect-[0.71] w-[1em] relative text-black"> 11 | <svg className="aspect-[0.71] absolute inset-0 z-30" fill="currentColor"> 12 | <use href={`/font-sprite.svg#char-${char}`} /> 13 | </svg> 14 | <svg className="aspect-[0.71] absolute inset-0 z-0 text-slate-400 opacity-10 dark:text-gray-950 dark:opacity-30" fill="currentColor"> 15 | <use href="/font-sprite.svg#char-8" /> 16 | <use href="/font-sprite.svg#char-i" /> 17 | </svg> 18 | </div> 19 | ); 20 | }; 21 | 22 | interface ClockFontProps { 23 | chars: string; 24 | } 25 | 26 | const ClockFont: React.FC<ClockFontProps> = ({ chars }) => { 27 | const words = chars.split(' '); 28 | 29 | return ( 30 | <div className="flex flex-wrap justify-center"> 31 | {words.map((word, i) => ( 32 | <div key={i} className="inline-flex mr-4"> 33 | {word.split('').map((char) => ( 34 | <ClockCharacter 35 | key={char} 36 | char={char} 37 | /> 38 | ))} 39 | </div> 40 | ))} 41 | </div> 42 | ); 43 | }; 44 | 45 | export default ClockFont; 46 | -------------------------------------------------------------------------------- /src/components/demo/DigitalSignalWave.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | 3 | const DigitalSignalWave = () => { 4 | // Simulated data for the signal (1s and 0s) 5 | const initialSignalData = [1, 0, 1, 0, 1, 1, 0, 0, 1, 0]; 6 | const [signalData, setSignalData] = useState(initialSignalData); 7 | 8 | useEffect(() => { 9 | // Shift the bars to the left every second 10 | const interval = setInterval(() => { 11 | setSignalData((prevData) => { 12 | const newData = [...prevData]; 13 | newData.shift(); // Remove the first element 14 | const randomBit = Math.random() < 0.5 ? 0 : 1; // Generate a random 0 or 1 15 | newData.push(randomBit); // Add the new random bit at the end 16 | return newData; 17 | }); 18 | }, 1000); 19 | 20 | return () => clearInterval(interval); // Clean up the interval 21 | }, []); 22 | 23 | return ( 24 | <div className="relative"> 25 | {/* Signal bars */} 26 | {signalData.map((bit, index) => ( 27 | <div 28 | key={index} 29 | className={`absolute bottom-0 h-${bit === 1 ? '10' : '4'} w-4 ${ 30 | bit === 1 ? 'bg-green-500' : 'bg-red-500' 31 | }`} 32 | style={{ left: `${index * 20}px` }} // Adjust spacing between bars 33 | > 34 | {/* Number (1 or 0) centered under the bar */} 35 | <div className="text-xs text-center mt-1 absolute w-full bottom-0"> 36 | {bit} 37 | </div> 38 | </div> 39 | ))} 40 | </div> 41 | ); 42 | }; 43 | 44 | export default DigitalSignalWave; 45 | -------------------------------------------------------------------------------- /src/global.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | @keyframes fadeNewChatMessage { 4 | 0% { opacity: 0; transform: translateY(1rem); } 5 | 100% { opacity: 1; transform: translateY(0px); } 6 | } 7 | 8 | .message-animation { 9 | animation: fadeNewChatMessage 0.5s; 10 | } 11 | -------------------------------------------------------------------------------- /src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | //_app.tsx 2 | import type { AppProps } from 'next/app'; 3 | import Head from 'next/head'; // Import the Head component 4 | import Script from 'next/script'; 5 | import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; 6 | import '../global.css'; // Import your global styles if you have any 7 | 8 | const queryClient = new QueryClient(); 9 | 10 | const MyApp = ({ Component, pageProps }: AppProps) => { 11 | return ( 12 | <> 13 | <Head> 14 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 15 | <meta name="description" content="Discover 'Lost Language of the Machines,' an interactive storybook where kids learn about computing with friends from the future. Start the adventure now!" /> 16 | <title>Lost Language of the Machines 17 | 18 | 28 |