[READ-ONLY] Mirror of https://github.com/flo-bit/flo-bit.github.io. my personal website, w/ astro, svelte, tailwind, typescript, threlte flo-bit.dev/
portfolio portfolio-website svelte sveltekit tailwind threejs threlte typescript
0

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #35 from flo-bit/new-version

fix firefox bug

author
Florian
committer
GitHub
date (Jan 2, 2025, 12:57 AM +0100) commit 5c0eebec parent ea91a046
+491 -338
-1
src/components/Hero/3D/PlanetScene.svelte
··· 1 1 <script lang="ts"> 2 2 import Scene from "./Scene.svelte"; 3 - import state from "./state.json"; 4 3 5 4 import { Canvas } from "@threlte/core"; 6 5
+13 -4
src/components/Hero/3D/Scene.svelte
··· 96 96 previousPointerPosition.set(clientX, clientY); 97 97 totalMove.set(0, 0); 98 98 99 - if (event instanceof TouchEvent) { 99 + if (window.TouchEvent && event instanceof window.TouchEvent) { 100 100 event.preventDefault(); // Prevent scrolling 101 101 } 102 102 }; ··· 142 142 143 143 export let pos = 0; 144 144 145 - let redo: () => void; 145 + let redo: () => Promise<void>; 146 146 </script> 147 147 148 148 <T.PerspectiveCamera ··· 193 193 <T.SphereGeometry args={[1.2, 8, 8]} /> 194 194 <T.MeshBasicMaterial /> 195 195 </T.Mesh> 196 - <PlanetModel bind:redo /> 196 + 197 + <Suspense> 198 + {#snippet fallback()} 199 + 200 + <T.Mesh> 201 + <T.IcosahedronGeometry args={[1.1, 8, 8]} /> 202 + <T.MeshStandardMaterial wireframe wireframeLinewidth={500} /> 203 + </T.Mesh> 204 + {/snippet} 205 + <PlanetModel bind:redo /> 206 + </Suspense> 197 207 </T.Group> 198 - 199 208 <!-- <CustomRenderer /> --> 200 209 201 210 <Stars />
-1
src/components/Hero/3D/worlds/helper/octree.ts
··· 237 237 q = this.query(opts.p, opts.min); 238 238 239 239 for (const point of q) { 240 - // @ts-expect-error - close is not a property of Vector3 241 240 point.close = true; 242 241 } 243 242 }
+59 -65
src/components/Hero/3D/worlds/models.ts
··· 1 1 import * as THREE from "three"; 2 2 import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; 3 - import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js"; 4 3 5 - const basePath = ''; 4 + const basePath = ""; 6 5 7 6 const lowPolyNatureCollectionModels: Record< 8 7 string, ··· 88 87 } 89 88 90 89 export function getModelPathsAndMaterials( 91 - name: string, 92 - collection: Collections = 'lowpoly_nature' 90 + name: string, 91 + collection: Collections = "lowpoly_nature", 93 92 ): { 94 - filePaths: string[]; 95 - materials: string[]; 93 + filePaths: string[]; 94 + materials: string[]; 96 95 } | null { 97 - const model = collections[collection].models[name]; 98 - if (!model) { 99 - console.error(`Model ${name} not found.`); 100 - return null; 101 - } 96 + const model = collections[collection].models[name]; 97 + if (!model) { 98 + console.error(`Model ${name} not found.`); 99 + return null; 100 + } 102 101 103 - // Construct file paths based on the number of versions 104 - const filePaths: string[] = []; 105 - if (model.versions) { 106 - for (let i = 1; i <= model.versions; i++) { 107 - filePaths.push(`${basePath}${collections[collection].name}/${name}_${i}-transformed.glb`); 108 - } 109 - } else { 110 - filePaths.push(`${basePath}${collections[collection].name}/${name}-transformed.glb`); 111 - } 102 + // Construct file paths based on the number of versions 103 + const filePaths: string[] = []; 104 + if (model.versions) { 105 + for (let i = 1; i <= model.versions; i++) { 106 + filePaths.push( 107 + `${basePath}${collections[collection].name}/${name}_${i}.gltf`, 108 + ); 109 + } 110 + } else { 111 + filePaths.push(`${basePath}${collections[collection].name}/${name}.gltf`); 112 + } 112 113 113 - return { 114 - filePaths, 115 - materials: model.materials 116 - }; 114 + return { 115 + filePaths, 116 + materials: model.materials, 117 + }; 117 118 } 119 + 118 120 export async function loadModels( 119 - name: string, 120 - collection: Collections = 'lowpoly_nature' 121 + name: string, 122 + collection: Collections = "lowpoly_nature", 121 123 ): Promise<THREE.Object3D[]> { 122 - const loader = new GLTFLoader(); 123 - const dracoLoader = new DRACOLoader(); 124 - dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/'); 125 - loader.setDRACOLoader(dracoLoader); 126 - 127 - const modelInfo = getModelPathsAndMaterials(name, collection); 124 + const loader = new GLTFLoader(); 125 + const modelInfo = getModelPathsAndMaterials(name, collection); 128 126 129 - if (!modelInfo) { 130 - return []; 131 - } 127 + if (!modelInfo) { 128 + return []; 129 + } 132 130 133 - const promises = modelInfo.filePaths.map((filePath) => { 134 - return new Promise<THREE.Object3D>((resolve, reject) => { 135 - loader.load( 136 - filePath, 137 - (gltf) => { 138 - gltf.scene.userData = { 139 - name, 140 - path: filePath 141 - }; 142 - gltf.scene.traverse((child) => { 143 - if (child instanceof THREE.Mesh) { 144 - child.receiveShadow = true; 145 - child.castShadow = false; 146 - } 147 - }); 148 - resolve(gltf.scene); 149 - }, 150 - undefined, 151 - (error) => { 152 - console.error(`Failed to load model ${filePath}:`, error); 153 - reject(error); 154 - } 155 - ); 156 - }); 157 - }); 131 + const promises = modelInfo.filePaths.map((filePath) => { 132 + return new Promise<THREE.Object3D>((resolve, reject) => { 133 + loader.load( 134 + filePath, 135 + (gltf) => { 136 + gltf.scene.userData = { 137 + name, 138 + path: filePath, 139 + }; 140 + gltf.scene.traverse((child) => { 141 + if (child instanceof THREE.Mesh) { 142 + child.receiveShadow = true; 143 + child.castShadow = false; 144 + } 145 + }); 146 + resolve(gltf.scene); 147 + }, 148 + undefined, 149 + (error) => { 150 + console.error(`Failed to load model ${filePath}:`, error); 151 + reject(error); 152 + }, 153 + ); 154 + }); 155 + }); 158 156 159 - let models = Promise.all(promises) 160 - models.then(() => { 161 - dracoLoader.dispose(); 162 - }) 163 - return models; 157 + return Promise.all(promises); 164 158 }
+4 -4
src/components/Hero/3D/worlds/planet.ts
··· 130 130 131 131 if (this.options.material === "caustics") { 132 132 planetMesh.onBeforeRender = ( 133 - _renderer, 134 - _scene, 135 - _camera, 136 - _geometry, 133 + renderer, 134 + scene, 135 + camera, 136 + geometry, 137 137 material, 138 138 ) => { 139 139 if (material instanceof PlanetMaterialWithCaustics) {
+255 -252
src/components/Hero/3D/worlds/presets.ts
··· 1 - import { type BiomeOptions } from './biome'; 2 - import { type PlanetOptions } from './planet'; 1 + import { type BiomeOptions } from "./biome"; 2 + import { type PlanetOptions } from "./planet"; 3 3 4 4 const beachBiome: BiomeOptions = { 5 - noise: { 6 - min: -0.05, 7 - max: 0.05, 8 - octaves: 4, 9 - lacunarity: 2.0, 10 - gain: { 11 - min: 0.1, 12 - max: 0.8, 13 - scale: 2 14 - }, 15 - warp: 0.3, 16 - scale: 1, 17 - power: 1.5 18 - }, 5 + noise: { 6 + min: -0.05, 7 + max: 0.05, 8 + octaves: 4, 9 + lacunarity: 2.0, 10 + gain: { 11 + min: 0.1, 12 + max: 0.8, 13 + scale: 2, 14 + }, 15 + warp: 0.3, 16 + scale: 1, 17 + power: 1.5, 18 + }, 19 19 20 - colors: [ 21 - [-0.5, 0x994400], 22 - [-0.0, 0xccaa00], 23 - [0.4, 0xcc7700], 24 - [1.0, 0x002222] 25 - ], 20 + colors: [ 21 + [-0.5, 0x994400], 22 + [-0.0, 0xccaa00], 23 + [0.4, 0xcc7700], 24 + [1.0, 0x002222], 25 + ], 26 26 27 - seaColors: [ 28 - [-1, 0x000066], 29 - [-0.55, 0x0000aa], 30 - [-0.1, 0x00f2e5] 31 - ], 32 - seaNoise: { 33 - min: -0.008, 34 - max: 0.008, 35 - scale: 6 36 - }, 27 + seaColors: [ 28 + [-1, 0x000066], 29 + [-0.55, 0x0000aa], 30 + [-0.1, 0x00f2e5], 31 + ], 32 + seaNoise: { 33 + min: -0.008, 34 + max: 0.008, 35 + scale: 6, 36 + }, 37 37 38 - vegetation: { 39 - items: [ 40 - { 41 - name: 'PalmTree', 42 - density: 50, 43 - minimumHeight: 0.1, 44 - colors: { 45 - Brown: { array: [0x8b4513, 0x5b3105] }, 46 - Green: { array: [0x22851e, 0x22a51e] }, 47 - DarkGreen: { array: [0x006400] } 48 - }, 49 - ground: { 50 - color: 0x229900, 51 - radius: 0.1, 52 - raise: 0.01 53 - } 54 - } 55 - ] 56 - } 38 + vegetation: { 39 + items: [ 40 + { 41 + name: "Rock", 42 + density: 50, 43 + minimumHeight: 0.1, 44 + colors: { 45 + Gray: { array: [0x775544] }, 46 + }, 47 + }, 48 + { 49 + name: "PalmTree", 50 + density: 50, 51 + minimumHeight: 0.1, 52 + colors: { 53 + Brown: { array: [0x8b4513, 0x5b3105] }, 54 + Green: { array: [0x22851e, 0x22a51e] }, 55 + DarkGreen: { array: [0x006400] }, 56 + }, 57 + ground: { 58 + color: 0x229900, 59 + radius: 0.1, 60 + raise: 0.01, 61 + }, 62 + }, 63 + ], 64 + }, 57 65 }; 58 66 59 67 const forestBiome: BiomeOptions = { 60 - noise: { 61 - min: -0.05, 62 - max: 0.05, 63 - octaves: 4, 64 - lacunarity: 2.0, 65 - gain: { 66 - min: 0.1, 67 - max: 0.8, 68 - scale: 2 69 - }, 70 - warp: 0.3, 71 - scale: 1, 72 - power: 0.8 73 - }, 68 + noise: { 69 + min: -0.05, 70 + max: 0.05, 71 + octaves: 4, 72 + lacunarity: 2.0, 73 + gain: { 74 + min: 0.1, 75 + max: 0.8, 76 + scale: 2, 77 + }, 78 + warp: 0.3, 79 + scale: 1, 80 + power: 0.8, 81 + }, 74 82 75 - tintColor: 0x113322, 83 + tintColor: 0x113322, 76 84 77 - colors: [ 78 - [-0.5, 0x332200], 79 - [-0.0, 0x115512], 80 - [0.4, 0x224411], 81 - [1.0, 0x006622] 82 - ], 85 + colors: [ 86 + [-0.5, 0x332200], 87 + [-0.0, 0x115512], 88 + [0.4, 0x224411], 89 + [1.0, 0x006622], 90 + ], 83 91 84 - seaColors: [ 85 - [-1, 0x000066], 86 - [-0.52, 0x0000aa], 87 - [-0.1, 0x0042a5] 88 - ], 89 - seaNoise: { 90 - min: -0.005, 91 - max: 0.005, 92 - scale: 5 93 - }, 92 + seaColors: [ 93 + [-1, 0x000066], 94 + [-0.52, 0x0000aa], 95 + [-0.1, 0x0042a5], 96 + ], 97 + seaNoise: { 98 + min: -0.005, 99 + max: 0.005, 100 + scale: 5, 101 + }, 94 102 95 - vegetation: { 96 - items: [ 97 - { 98 - name: 'Rock', 99 - density: 5, 100 - minimumHeight: 0.1, 101 - colors: { 102 - Gray: { array: [0x888888, 0x616161, 0x414141] } 103 - } 104 - }, 105 - { 106 - name: 'CommonTree', 107 - density: 5, 108 - minimumHeight: 0.0 109 - }, 110 - { 111 - name: 'Bush', 112 - density: 5, 113 - minimumHeight: 0.0 114 - }, 115 - { 116 - name: 'CommonTree_Dead', 117 - density: 5 118 - }, 119 - { 120 - name: 'PineTree', 121 - density: 5 122 - }, 123 - { 124 - name: 'TreeStump', 125 - density: 1 126 - }, 127 - { 128 - name: 'TreeStump_Moss', 129 - density: 1 130 - }, 131 - { 132 - name: 'Willow', 133 - density: 5 134 - }, 135 - { 136 - name: 'Willow_Dead', 137 - density: 5 138 - }, 139 - { 140 - name: 'WoodLog', 141 - density: 1 142 - }, 143 - { 144 - name: 'BirchTree', 145 - density: 5 146 - }, 147 - { 148 - name: 'BirchTree_Dead', 149 - density: 5 150 - } 151 - ] 152 - } 103 + vegetation: { 104 + items: [ 105 + { 106 + name: "Rock", 107 + density: 5, 108 + minimumHeight: 0.1, 109 + colors: { 110 + Gray: { array: [0x888888, 0x616161, 0x414141] }, 111 + }, 112 + }, 113 + { 114 + name: "CommonTree", 115 + density: 5, 116 + minimumHeight: 0.0, 117 + }, 118 + { 119 + name: "Bush", 120 + density: 5, 121 + minimumHeight: 0.0, 122 + }, 123 + { 124 + name: "CommonTree_Dead", 125 + density: 5, 126 + }, 127 + { 128 + name: "PineTree", 129 + density: 5, 130 + }, 131 + { 132 + name: "TreeStump", 133 + density: 1, 134 + }, 135 + { 136 + name: "TreeStump_Moss", 137 + density: 1, 138 + }, 139 + { 140 + name: "Willow", 141 + density: 5, 142 + }, 143 + { 144 + name: "Willow_Dead", 145 + density: 5, 146 + }, 147 + { 148 + name: "WoodLog", 149 + density: 1, 150 + }, 151 + { 152 + name: "BirchTree", 153 + density: 5, 154 + }, 155 + { 156 + name: "BirchTree_Dead", 157 + density: 5, 158 + }, 159 + ], 160 + }, 153 161 }; 154 162 155 163 const snowForestBiome: BiomeOptions = { 156 - noise: { 157 - min: -0.05, 158 - max: 0.05, 159 - octaves: 4, 160 - lacunarity: 2.0, 161 - gain: { 162 - min: 0.1, 163 - max: 0.8, 164 - scale: 2 165 - }, 166 - warp: 0.3, 167 - scale: 1, 168 - power: 0.8 169 - }, 164 + noise: { 165 + min: -0.05, 166 + max: 0.05, 167 + octaves: 4, 168 + lacunarity: 2.0, 169 + gain: { 170 + min: 0.1, 171 + max: 0.8, 172 + scale: 2, 173 + }, 174 + warp: 0.3, 175 + scale: 1, 176 + power: 0.8, 177 + }, 170 178 171 - tintColor: 0x119922, 179 + tintColor: 0x119922, 172 180 173 - colors: [ 174 - [-0.5, 0xff99ff], 175 - [-0.0, 0xffffff], 176 - [0.4, 0xeeffff], 177 - [1.0, 0xffffff] 178 - ], 181 + colors: [ 182 + [-0.5, 0xff99ff], 183 + [-0.0, 0xffffff], 184 + [0.4, 0xeeffff], 185 + [1.0, 0xffffff], 186 + ], 179 187 180 - seaColors: [ 181 - [-1, 0x8899cc], 182 - [-0.52, 0xaaccff], 183 - [-0.1, 0xaaccff] 184 - ], 185 - seaNoise: { 186 - min: -0.0, 187 - max: 0.001, 188 - scale: 5 189 - }, 188 + seaColors: [ 189 + [-1, 0x8899cc], 190 + [-0.52, 0xaaccff], 191 + [-0.1, 0xaaccff], 192 + ], 193 + seaNoise: { 194 + min: -0.0, 195 + max: 0.001, 196 + scale: 5, 197 + }, 190 198 191 - vegetation: { 192 - items: [ 193 - { 194 - name: 'Rock_Snow', 195 - density: 5, 196 - minimumHeight: 0.1, 197 - colors: { 198 - Gray: { array: [0x888888, 0x616161, 0x414141] } 199 - } 200 - }, 201 - { 202 - name: 'CommonTree_Snow', 203 - density: 5, 204 - minimumHeight: 0.0 205 - }, 206 - { 207 - name: 'Bush_Snow', 208 - density: 5, 209 - minimumHeight: 0.0 210 - }, 211 - { 212 - name: 'CommonTree_Dead_Snow', 213 - density: 5 214 - }, 215 - { 216 - name: 'PineTree_Snow', 217 - density: 5 218 - }, 219 - { 220 - name: 'TreeStump_Snow', 221 - density: 1 222 - }, 223 - { 224 - name: 'TreeStump_Snow', 225 - density: 1 226 - }, 227 - { 228 - name: 'Willow_Snow', 229 - density: 5 230 - }, 231 - { 232 - name: 'Willow_Dead_Snow', 233 - density: 5 234 - }, 235 - { 236 - name: 'WoodLog_Snow', 237 - density: 1 238 - }, 239 - { 240 - name: 'BirchTree_Snow', 241 - density: 5 242 - }, 243 - { 244 - name: 'BirchTree_Dead_Snow', 245 - density: 5 246 - } 247 - ] 248 - } 199 + vegetation: { 200 + items: [ 201 + { 202 + name: "Rock_Snow", 203 + density: 5, 204 + minimumHeight: 0.1, 205 + colors: { 206 + Gray: { array: [0x888888, 0x616161, 0x414141] }, 207 + }, 208 + }, 209 + { 210 + name: "CommonTree_Snow", 211 + density: 5, 212 + minimumHeight: 0.0, 213 + }, 214 + { 215 + name: "Bush_Snow", 216 + density: 5, 217 + minimumHeight: 0.0, 218 + }, 219 + { 220 + name: "CommonTree_Dead_Snow", 221 + density: 5, 222 + }, 223 + { 224 + name: "PineTree_Snow", 225 + density: 5, 226 + }, 227 + { 228 + name: "TreeStump_Snow", 229 + density: 1, 230 + }, 231 + { 232 + name: "TreeStump_Snow", 233 + density: 1, 234 + }, 235 + { 236 + name: "Willow_Snow", 237 + density: 5, 238 + }, 239 + { 240 + name: "Willow_Dead_Snow", 241 + density: 5, 242 + }, 243 + { 244 + name: "WoodLog_Snow", 245 + density: 1, 246 + }, 247 + { 248 + name: "BirchTree_Snow", 249 + density: 5, 250 + }, 251 + { 252 + name: "BirchTree_Dead_Snow", 253 + density: 5, 254 + }, 255 + ], 256 + }, 249 257 }; 250 258 251 259 export const biomePresets: Record<string, BiomeOptions> = { 252 - beach: beachBiome, 253 - forest: forestBiome, 254 - snowForest: snowForestBiome 260 + beach: beachBiome, 261 + forest: forestBiome, 262 + snowForest: snowForestBiome, 255 263 }; 256 264 257 265 const beachPlanet: PlanetOptions = { 258 - biome: { 259 - preset: 'beach' 260 - }, 261 - atmosphere: { 262 - enabled: false 263 - }, 264 - material: 'normal' 266 + biome: { 267 + preset: "beach", 268 + }, 269 + 270 + material: "caustics", 265 271 }; 266 272 267 273 const forestPlanet: PlanetOptions = { 268 - biome: { 269 - preset: 'forest' 270 - }, 274 + biome: { 275 + preset: "forest", 276 + }, 271 277 272 - material: 'normal', 273 - atmosphere: { 274 - enabled: false 275 - } 278 + material: "normal", 276 279 }; 277 280 278 281 const snowForestPlanet: PlanetOptions = { 279 - biome: { 280 - preset: 'snowForest' 281 - } 282 + biome: { 283 + preset: "snowForest", 284 + }, 282 285 }; 283 286 284 287 export const planetPresets: Record<string, PlanetOptions> = { 285 - beach: beachPlanet, 286 - forest: forestPlanet, 287 - snowForest: snowForestPlanet 288 + beach: beachPlanet, 289 + forest: forestPlanet, 290 + snowForest: snowForestPlanet, 288 291 };
+77
src/components/Hero/3D/worlds/stars.ts
··· 1 + import * as THREE from "three"; 2 + 3 + export type StarsOptions = { 4 + particleCount: number; 5 + minimumDistance: number; 6 + maximumDistance: number; 7 + }; 8 + 9 + export class Stars extends THREE.Group { 10 + private particleCount: number = 5000; 11 + 12 + private minimumDistance: number = 10; 13 + private maximumDistance: number = 20; 14 + 15 + private positions: Float32Array; 16 + private colors: Float32Array; 17 + private geometry: THREE.BufferGeometry; 18 + private material: THREE.PointsMaterial; 19 + private particles: THREE.Points; 20 + 21 + private tempVector = new THREE.Vector3(); 22 + 23 + constructor(opts: Partial<StarsOptions> = {}) { 24 + super(); 25 + 26 + this.particleCount = opts.particleCount ?? this.particleCount; 27 + this.minimumDistance = opts.minimumDistance ?? this.minimumDistance; 28 + this.maximumDistance = opts.maximumDistance ?? this.maximumDistance; 29 + 30 + this.positions = new Float32Array(this.particleCount * 3); 31 + this.colors = new Float32Array(this.particleCount * 3); 32 + 33 + this.setupParticles(); 34 + } 35 + 36 + private setupParticles() { 37 + for (let i = 0; i < this.particleCount; i++) { 38 + this.resetParticle(i); 39 + } 40 + 41 + this.geometry = new THREE.BufferGeometry(); 42 + this.geometry.setAttribute( 43 + "position", 44 + new THREE.BufferAttribute(this.positions, 3), 45 + ); 46 + this.geometry.setAttribute( 47 + "color", 48 + new THREE.BufferAttribute(this.colors, 3), 49 + ); 50 + 51 + this.material = new THREE.PointsMaterial({ 52 + size: 0.04, 53 + vertexColors: true, 54 + }); 55 + 56 + this.particles = new THREE.Points(this.geometry, this.material); 57 + 58 + this.add(this.particles); 59 + } 60 + 61 + private resetParticle(i: number) { 62 + const index = i * 3; 63 + 64 + const distance = 65 + Math.random() * (this.maximumDistance - this.minimumDistance) + 66 + this.minimumDistance; 67 + this.tempVector.randomDirection().multiplyScalar(distance); 68 + 69 + this.positions[index] = this.tempVector.x; 70 + this.positions[index + 1] = this.tempVector.y; 71 + this.positions[index + 2] = this.tempVector.z; 72 + 73 + this.colors[index] = Math.random() < 0.2 ? 0.3 : 1.0; 74 + this.colors[index + 1] = Math.random() < 0.2 ? 0.3 : 1.0; 75 + this.colors[index + 2] = Math.random() < 0.2 ? 0.3 : 1.0; 76 + } 77 + }
+78
src/content/blog/how-to-become-a-great-programmer.md
··· 1 + --- 2 + title: 'How to become a Great Programmer (or anything else)' 3 + description: 'in just one easy step' 4 + pubDate: '2024-02-08' 5 + published: true 6 + tags: ['astro', 'blog', 'test'] 7 + --- 8 + 9 + ## The one easy step: 10 + 11 + 👏 Just 👏 do 👏 the 👏 fucking 👏 thing 👏 12 + 13 + Yes, it’s that easy. *Practice makes perfect* may be clichéd but it’s absolutely true in my experience. 14 + 15 + “But how exactly do I do the thing?” you may ask. I’ll draw up a rough roadmap for learning programming assuming you currently don’t have any coding skills. This is of course a method that works for me and should be fitted to your personality/skills/the thing you want to learn. Experimentation is your friend there. 16 + 17 + ## The first project 18 + 19 + Should be something that is not super hard (so, yeah, your MMORPG idea will have to wait), otherwise anything goes (if you’re not sure if your idea is too hard, just try it, you’ll find out). Don’t have an idea? Ask Chad for some ideas: describe your skill level and any “requirements” you have like “i want to make a game” or “something that runs on my apple watch”, then use your favourite suggestion or the first one (if you can’t decide). Don’t take much longer than ~10 minutes to pick a project. 20 + 21 + ## The right framework and language 22 + 23 + Doesn’t really matter. Pick any one (again Chad can be very helpful, describe your situation like this example: “I'm starting to learn programming and want to make a website that translates any text into emojis. whats the best framework and language to do that with?” and then when Chad gives you way to many options, pick a random one). If you don’t like it, use something else for your next project (maybe do that, even if you do like it). 24 + 25 + ## On tutorials (and Chad) 26 + 27 + Yes, tutorials are great and can be a good first reference point. Same goes for Chad just writing all the code for you, but while fast and easy it does sadly limit the amount you learn by quite a lot. I love Chad as much as anyone, but copy-pasting code is not the same as writing code. If you really want to follow a tutorial or Chad, a method I like to do is one-with one-solo (or something like that, I didn’t invent that, I’m sure there is an actual name for that), where first you follow along and then you repeat it, doing it yourself. My preferred way though is to look up stuff whenever you don’t know how to do a specific thing and then keep going. 28 + 29 + ## “You just want me to fail!”, you say 30 + 31 + Yes! That’s exactly what I want! “Wait, what! You fucker!” But no joking, failure is where learning happens. You don’t learn to walk without first falling on your face a lot. It turns out walking is just falling over and over again and catching yourself in time. Is this metaphor still working? 32 + 33 + Anyway for me, if I start something with the mindset of “I’m gonna fail a lot doing this and that’s okay” it helps me avoid a lot of the frustration that occurs when I inevitably do get stuck with an annoying bug or can’t get something to work. That being said, don’t forget to… 34 + 35 + ## Have fun! 36 + 37 + Motivation is where I often struggle as well. Again starting your journey with the explicit intent of “Yes, I want to learn something, but I also want to have fun doing it!” helps me personally. Switching from one project to another also often helps (and yes that makes both projects less likely to be a success/finished, but we don’t really care about that, we’re here to learn) as does taking breaks (but not too long otherwise you may never start again). 38 + 39 + ## I finished my project and it’s horrible OR I couldn’t do it 40 + 41 + That was always the most likely outcome! There’s a folder in my computer with my failed/abandoned projects and it’s larger than all my other folders put together. So don’t despair, just remember to… 42 + 43 + ## Reflect 44 + 45 + What went wrong? What did I learn? What should I do differently next time? Was my project way to ambitious for my current skill? Was it actually too easy and I didn’t really learn anything? 46 + 47 + ## Repeat 48 + 49 + It’s time to do it all over again. Pick a new project (varying difficulty, etc.) and off you go! 50 + 51 + ## This works for lots of things (for me) 52 + 53 + So first, again the disclaimer that this works for me and doesn’t necessarily work for you in exactly the same way. But give it a try if you want and then adjust it to your liking. 54 + 55 + This also works for lots of other things apart from coding, some examples are: 56 + 57 + - Cooking 58 + 59 + Start with simple recipes, once you made some that are edible, level up the difficulty, maybe let someone else try it at some point 60 + 61 + - Languages 62 + 63 + Do a few weeks of doulingo, reread an easy book you’ve already read in that language, watch a tv show, chat with chad in that language, find someone to practice with and speak with them 64 + 65 + - 3D modeling 66 + 67 + Start with a super easy model (maybe a donut? sidenote: that guy is where I stole that one-with one-solo method from) then a harder one and so on 68 + 69 + - Writing 70 + 71 + Maybe start a blog and try to write two articles a week and publish at least one (see this blog for an example) 72 + 73 + ## On sharing 74 + 75 + Sharing stuff you created can be super motivating and keep you going but it can also easily lead to perfectionism, which we want to avoid. In the end it depends on your skill level, personality and what you’re trying to learn. With this blog for example I want to learn to write better but I also want to learn to avoid perfectionism, so I kinda have to publish. 76 + 77 + *Final note: I just want to be clear that I don’t think that I am a “Great Programmer” (though I do think I’m decent, I have been doing this for a few years), but I do think I’m somewhere on the road to becoming a “Great Programmer” (and this is probably open-ended, I’ll never reach that, as there actually is no clearly defined goal. In the end the road is the goal, always keep learning!).* 78 +
-9
src/content/blog/test.md
··· 1 - --- 2 - title: 'test 123' 3 - description: 'this is the description' 4 - pubDate: '2024-11-27' 5 - published: true 6 - tags: ['astro', 'blog', 'test'] 7 - --- 8 - 9 - hello this is a test post.
+1 -1
src/layouts/BlogPost.astro
··· 2 2 import ProseWrapper from "./ProseWrapper.astro"; 3 3 --- 4 4 5 - <main class="w-full max-w-5xl mx-auto h-full p-4"> 5 + <main class="w-full max-w-2xl mx-auto h-full p-4 py-16"> 6 6 <ProseWrapper> 7 7 <slot /> 8 8 </ProseWrapper>
+1 -1
src/layouts/ProseWrapper.astro
··· 11 11 12 12 <div 13 13 class={cn( 14 - "prose prose-img:rounded-xl dark:prose-invert prose-a:no-underline", 14 + "prose prose-img:rounded-xl dark:prose-invert prose-a:no-underline max-w-full", 15 15 "prose-inline-code:bg-base-100 dark:prose-inline-code:bg-base-800 prose-inline-code:p-1 prose-inline-code:rounded-md", 16 16 colorBaseClasses[BASE_COLOR], 17 17 colorAccentClasses[ACCENT_COLOR],
+3
src/pages/index.astro
··· 9 9 import { getFeaturedProjects } from "src/utils"; 10 10 import Footer from "$components/Footer.astro"; 11 11 import Navbar from "$components/Navigation/Navbar.svelte"; 12 + import BlogLatest from "$components/Blog/BlogLatest.astro"; 12 13 13 14 const projects = await getFeaturedProjects(); 14 15 --- ··· 23 24 <About /> 24 25 25 26 <Projects projects={projects} /> 27 + 28 + <!-- <BlogLatest /> --> 26 29 27 30 <Learning client:visible /> 28 31