cho.sh
2,244 notes
Liked on XI made a mistake. When Jack and I decided to organize this $100K Hackathon, my biggest concern was cheating. Unlike a regular hackathon, everyone participates from home. And because the winner is whoever makes the most PROFIT (not revenue), there are so many ways to manipulate the numbers. So I added a $99 entry fee. One thing I’ve learned from building businesses is that people tend to be more committed when they pay for something. I thought it would filter out spam, attract serious builders, and make the competition fairer for everyone. But I completely missed the other side. 3 years ago, I was a living with my apps. Today, I’m financially free. My life changed so much that somewhere along the way, I lost perspective on what $99 means to someone else. For someone in India, someone struggling to pay their bills, or someone trying to make their first dollar online, $99 can be a lot of money. And those are exactly the people I want to help! I’ve spent years sharing what I’ve learned, reviewing random people’s landing pages, and organizing free meetups around the world. Not because there’s money to make, but because I genuinely love seeing people build things and succeed. And somehow, I was so focused on keeping cheaters out that I didn’t realize I was also keeping genuine builders out. That’s my mistake. So I’ve decided to make the $100K Hackathon completely FREE :) Everyone who already paid got a full refund. I’m still worried about cheating. That problem hasn’t disappeared, and Jack and I will have to figure out better ways to verify profits and keep the leaderboard fair. But that’s our problem to solve. Thank you to everyone who shared their thoughts. Sometimes you need people to remind you of things you’ve forgotten. I genuinely hope this hackathon changes someone’s life. ❤️Liked on XIt’s time to bring back Cafe CursorPosted on Xyo @pendev i can't live share edit a .pen file? it's the most needed featurePosted on XI'm coining a word "Agentsplaining" Agents condescendingly assuming the user don't know fuck and repeating the obviousReplied on X@jayhxmo @raycast Hard to explain. It's the small detailsPosted on X@raycast iOS keyboard is insanely good. Might resub Raycast pro just cuz of thisReplied on X@ishuagra02 I saw a theory that F5.2 is a post train of 5.1, but O5.5 is a distillation of F5.5(unreleased new pretrain) and thats why O5.5 > F5.2Liked on X@anaclumos don't know what is actually improved 👀Posted on Xam i the only one underimpressed with 5.2 fableReplied on X@bvvst great minds think alike https://t.co/YRFWhb1mcOLiked on XClaude Fable 5.2 is out and it's the perfect time to run this god-level prompt on your codebase: "I want you to audit our codebase, is anything here unnecessary, overly complicated in our current setup, or based on weak assumptions? Challenge them. - What can be deleted entirely? - What can be simplified now that unnecessary pieces are gone? Then make the changes. Prefer deleting over simplifying, simplifying over optimizing, and optimizing over automating. This product is being used by thousands of customers, do not cut any corners." This prompt is one I run often and leads to the best results.Replied on X@akshayadinesh19 @bot can we please BYOM for botsLiked on XTo be fair, the Chinese models have a much lower refusal rateLiked on XF*CK IT, im creating a library of AI slop indicators. my feed is full of taste larpers. stay tuned https://t.co/5Muv8nQRm3Liked on XJENSEN! THATS NOT WHAT WE MEANT BY CHINESE MODELS!!!!!!!Liked on Xmy parents had to declare bankruptcy when I was a kid, so they had every reason to pressure me towards a more stable career path instead, they were so patient with me, even as i failed startup after startup for years so getting to tell my mom that everything turned out okay was a really special moment :) for those who can't read Korean, her first message roughly translates to: "Really!!! Congratulations my son. So much :') Thank you God!" i know I've been posting about my exit for like a week now, but it really is a big deal for me and my family! i'll share more about how this all happened and some tactical advice later this week, but for now i'm just riding out all the emotions to quote my mom, thank you God!!!!Liked on X@thefarmers_Dog it stands for Egg GzampleLiked on X🦍 Introducing Memorilla: memory as a modality for LLMs Memorilla turns everything a frozen LLM needs to remember into just 16 memory embeddings ⚡ It uses up to 4,212× fewer tokens and is 27× faster than full context inference while more accurate 🎯 Pushes the Pareto frontier over RAG and agentic memory in personalization, long-document and knowledge QA A thread 🧵:Liked on XThere's a huge product opportunity downstream of Tailscale etc too. At @tldraw we've started designing for "high trust networks" and it's been a beautiful thing. 1. Features that would be a nightmare on the internet are okay on my computer and mostly okay on private networks. Websites that execute user-generated scripts, control production systems, allow for users to send desktop notifications, spend tokens, or directly prompt my agent. Crazy stuff that would only make sense if everyone was in a committed polycule. 2. When everyone on the server can be trusted to have _external_ reasons for good behavior (eg keeping their job, or maintaining friends, family, church, mafia org), the software can be designed in a default social way. Most apps default to isolation, low horizontal visibility, highly restricted collaboration. Makes sense if the social contracts are inside of the app, but if you can trust that they live outside of the app then you can get wild. Example being small group chat names as an emergent comedy phenomenon because anyone in the group can change the name. 3. This can work for commercial products, too, not just internal stuff. Security matters more than ever but the way we've seen that manifest is that more companies are more confident in their own solutions than anything we could provide, to the point where owning data and access is a better value proposition than having it managed. Always has been true for big companies but now even small companies can get a good secure network set up pretty easily, and the hooks we need to build are easy enough. tldraw offline got us started down this road (and shout out to @pendev for first introducing me to the idea of desktop + mcp). We've been bringing that product to private networks and it's been exciting to see how much we can get away with. Keep an eye outReplied on X@saradu birds eye viewLiked on XApplications close in 2 days!! If you have a cool bio idea, and $5-10k will go a long way for you, please apply!!! https://t.co/NCvmrNC53cLiked on XWe've been early adopters of Rust since 2018 and a lot of our infra, voice tech, and even some of the current client is already Rust, the holy grail was getting the whole client there. That means Electron goes away, and so does React Native, mobile keeps native UI but shares app code with desktop via Rust. We hope to get it into testing with users soon™. (And it's not Tauri, it's GPUI, so good guess everyone.) Alright, back to staring at the WoW Forever login screen.Reposted on XOh boy. https://t.co/X7SSskGuGvLiked on XRIP .si domain squatters
Snowpack으로 WASM 시작하기

Snowpack으로 WASM 시작하기

Warning

Over a year old. May be outdated

Source

이 글은 아래 튜토리얼을 공부하고 분석한 글이다. 이 글이 도움이 되었다면 내 저장소 대신 아래 저장소에 스타를 눌러주자.

과정

  • 다음 명령어로 create-snowpack-app을 써서 gif-converter라는 프로젝트를 생성한다.
bash
npx create-snowpack-app gif-converter --template @snowpack/app-template-react
  • 다음 명령어로 ffmpeg.wasm을 설치한다. (실제 WASM 파일은 사용자의 웹페이지에서는 CDN을 통해 async하게 로딩됨. 여기서 설치하는 것은 Wrapper인 것 같다.)
bash
npm install @ffmpeg/ffmpeg @ffmpeg/core
  • 그 다음 snowpack을 설치한다.
bash
npm install snowpack --save-dev
  • 다음 명령어로 테스트 가능하다. snowpack을 위 명령어로 설치하는 대신 npm i -g snowpack으로 글로벌하게 설치했다면 snowpack dev를 하면 된다.
bash
npm start
  • src/App.jsx
jsx
import  { useState, useEffect } from 'react'
import './App.css'

import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'
const ffmpeg = createFFmpeg({ log: true })

function App() {
  const [ready, setReady] = useState(false)
  const [video, setVideo] = useState()
  const [gif, setGif] = useState()

  const load = async () => {
    await ffmpeg.load()
    setReady(true)
  }

  useEffect(() => {
    load()
  }, []) // blank [] makes it run once.

  const convertToGif = async () => {
    // Write the file to memory
    ffmpeg.FS('writeFile', 'test.mp4', await fetchFile(video))

    // Run the FFMpeg command
    await ffmpeg.run(
      '-i', // input flag
      'test.mp4', // video source input
      '-t', // time flag
      '2.5', // for 2.5 seconds
      '-ss', // starting secont flag
      '2.0', // offset for 2 seconds
      '-f', // file
      'gif', // encode as gif file
      'out.gif' // write file to out.gif
    )

    // Read the result
    const data = ffmpeg.FS('readFile', 'out.gif')

    // Create a URL
    const url = URL.createObjectURL(new Blob([data.buffer], { type: 'image/gif' }))
    setGif(url)
  }

  return ready ? (
    <div className="App">
      {video && <video controls width="250" src={URL.createObjectURL(video)}></video>}
      <input type="file" onChange={(e) => setVideo(e.target.files?.item(0))} />
      <h3>Result</h3>
      <button onClick={convertToGif}>Convert</button>
      {gif && <img src={gif} width="250" />}
    </div>
  ) : (
    <p>Loading...
  )
}

export default App
  • FFMpeg는 in-memory file system을 사용한다.
  • 다음과 같은 형태의 JS 문법을 사용하여 gif가 JS 기준 false(null, undefined, false...)가 아닐 때만 렌더링되도록 만들 수 있다.
jsx
{
  gif && <img src={gif} width="250" />;
}

GitHub Pages에 Snowpack App 호스팅 및 시행착오

  • 으로 GitHub Pages에 띄우려고 했다. 그런데 _dist_ 폴더의 index.html에서 404 Not Found가 발생했다.
  • 빌드하면서 docs 폴더 및 build 폴더를 초기화하는 스크립트 추가 (기존 방식에서도 포함하고 있는 기능인데 처음에는 단순히 폴더명을 build에서 docs로 바꾸는 기능만 넣고 이 부분을 포함하지 않았다.) 문제가 해결되지 않았다.
  • gh-pages를 사용해보았다. 문제가 해결되지 않았다.
  • 그 다음 touch docs/.nojekyll해보았다. 작동하지 않았다. (나중에 알게 됐지만 이게 해결책이었다. GitHub Pages가 Environment 탭에서는 Deploy 되었다고 나타나는데 반해 실제로는 업데이트되지 않아서 이게 해결책이 아닌 줄 알았다.)
  • 또 다음과 같이 snowpack.config.js에서 baseUrl을 변경해주었다. (이것도 필요한 해결책이었다. 나의 GitHub Pages는 subdirectory에 호스팅하기 때문에 이와 같은 옵션이 필요하다. 참고 링크 1, 참고 링크 2)
js
buildOptions: {
  baseUrl: '/ffmpeg-wasm-gif-converter-study/',
},
  • Production 폴더의 _dist_ 디렉토리의 이름을 static으로 변경했다. 이는 snowpack.config.js에서 다음 코드를 변경함으로써 가능하다. (실제로는 불필요한 변경이었다.)
js
mount: {
  public: '/',
  src: '/static',
},
  • 이는 또한 public/index.html에서 src를 변경해주었다. 위의 Discussion Post들을 볼 때 여기를 %PUBLIC_URL%으로 해야하는 것 같은데, 일단 ./static/index.js을 사용했다. 이를 통해서 index.html은 로딩되었다.
html
<script type="module" src="./static/index.js"></script>
  • 하지만 여전히 _snowpack_ 폴더 내부의 파일이나 web_modules 폴더 내의 결과물은 404 Not Found 상태였다.
  • 이때부터 GitHub Pages가 _ 폴더를 인식하지 못한다는 것을 알게 되었다.
  • 약간의 조사를 해 보니 GitHub Pages에 기본으로 포함된 Jekyll 전처리 기능 때문이라는 것을 알게 되었다. 참고 링크
  • 때문에 다시 .nojekyll 파일을 추가해보았다. npm run build 명령어를 다시 수정해 다음 명령어를 추가했다. 이를 통해 프로젝트를 build할 때마다 자동으로 .nojekyll 파일이 추가되도록 만들었다.
bash
... && touch docs/.nojekyll
  • 여전히 문제가 발생했다. 조사를 해보니 GitHub Pages가 Environment 탭에서는 Deploy 되었다고 나오는데 실제로는 업데이트되는데 시간이 더 걸리는 문제인 것 같았다. 참고 링크
  • 웹앱의 title도 바꿔봤는데 Production 웹사이트에서는 변경되지 않는 것을 볼 때 업데이트에 약간의 시간이 걸리는 것이라고 판단했다.
  • 웹앱이 업데이트되고 난 후 _snowpack_/env.js가 정상적으로 로딩됨을 확인했다. 하지만 여전히 web_modules는 404 Not Found가 나타났다.
  • create-snowpack-app을 쓸 경우 .gitignore에 web_modues가 추가되는 문제 때문이었다. 원래 web_modules는 GitHub에 node_module처럼 안 올라가야 맞는데, 지금의 경우에는 GitHub을 CDN처럼 활용하는 것으므로 web_modules가 필요하다.
  • 정상적으로 동작함을 확인했다.
  • 다만 Safari와 에서는 작동되지 않았다. " is not defined"이라는 오류가 발생했다.
  • 조사해본 결과 ffmpeg.wasm은 현재 Chrome에서만 동작하기 때문이라고 한다 (참고 링크 1.) ffmpeg.wasm 공식 데모 사이트에 Safari나 로 접근하면 다음 오류가 나타난다.

Your browser doesn't support , thus ffmpeg.wasm cannot execute. Please use latest version of Chromium or any other browser supports .

해결책 정리

Create-Snowpack-App을 GitHub Pages에 올리기 위해서는 다음을 해야한다.

  • 빌드 결과물에 .nojekyll 파일 추가하기
  • snowpack.config.js에 buildOptions.baseUrl 추가하기
  • GitHub Pages는 업데이트에 시간이 조금 걸리니 충분히 기다리기
  • ffmpeg.wasm은 Chrome을 사용해 구동하기 (2020/11 기준)

완성본

아쉬운 점

  • Random Commit이 많았다. GitHub Pages에 정상적으로 결과가 반영되는지를 확인하기 위해 일단 업로드해야했기 때문이다. 결과적으로 GitHub의 설정 (.nojekyll 등) 때문에 오류가 발생됐던 것이라 불가피했다고 생각한다.
Backlinks1