Premium transition-in for the scrolled page, in the instrument voice:
- Structural draw-up, scrub-linked and reversible: as a section enters
the viewport its top rule DRAWS across, the eyebrow's mono contents
settle in, and the corner ticks pop — all tied to scroll position
(scrub 0.35), so pulling back down un-draws the frame. Content
reveals stay one-shot: text never wiggles under the reader. Rules
render complete in server HTML; only motion-capable visitors get
the choreography.
- Section eyebrows ("01 / Crafting features") are sticky while their
section scrolls — frosted (backdrop blur over translucent page
background) like the ruler rail, pinned under the navbar, pushed
away by the next section rather than stacking.
- The studio demo moves out of the hero into Features as the lead
cell: the announce strip becomes its header row and the
blocking↔render comparator its 21:9 body (cursor hint as an
invert chip over the footage, md+ only). The hero ends at the
poster. Image to Location returns to the grid, which now splits
evenly: seven feature cells plus a full-sized eighth cell — the
launch CTA, a clickable door to the webapp with an arrow chip
and the same header/body/copy anatomy as its siblings.
Verified in Firefox: rule at 52% mid-viewport and back to 0 on
scroll-back (reversible), eyebrow pinned at 48px deep into the
section, zero page errors.
Claude-Session: https://claude.ai/code/session_01YBoaBEt3gynzTwogBFtn4B
Frontend
This is the Nx workspace for ArtCraft web apps and shared libraries. The desktop frontend is maintained in storytold/artcraft.
All commands to run these projects are performed from this directory (except the repo-root launcher scripts noted below).
Requirements
- Node.js 20+ (Nx 21 / Vite 6 requirement). Install via nvm,
nodejs.org, or
brew install node. - npm (ships with Node).
We use npm, not pnpm. pnpm was briefly adopted ("add pnpm to solve build issues") and later removed ("fix(frontend): consume video-editor libs via nx path aliases, drop pnpm"). If you have leftovers from that era — a
pnpm-lock.yaml,pnpm-workspace.yaml, or anode_modules/.pnpmdirectory — npm installs will fail (typically withENOTEMPTYrename errors). See Troubleshooting below.
Install dependencies
npm install
Running the apps in dev mode
From the repository root, the launcher scripts (these preflight your environment, install dependencies, and free the dev port first):
./script/website/unix_frontend_website_dev.sh # artcraft-website (marketing site), port 4200
./script/website/unix_frontend_webapp_dev.sh # artcraft-webapp (user dashboard), port 4201
Or directly from this directory:
nx dev artcraft-website
nx dev artcraft-webapp
Building
npx nx build artcraft-website
npx nx build artcraft-webapp
Netlify deploys run apps/<app>/script/netlify_build.sh (see each app's
netlify.toml).
Troubleshooting
npm install fails with ENOTEMPTY: directory not empty, rename ...
Your node_modules tree is corrupted — usually an interrupted install, or a
tree written by pnpm back when the repo briefly used it. Fix:
./clean_modules.sh
npm install
Or the manual minimum:
rm -rf node_modules .nx pnpm-lock.yaml pnpm-workspace.yaml
npm install
Stale build state after switching branches
Call this when starting on main or a new branch:
./clean_modules.sh
It removes all dist/ outputs, resets the nx cache, and removes
node_modules.
Import aliases
The names for @frontend and @storyteller come from the package.json file
in the libs folder:
import { Login } from "@frontend/login";
import { api } from "@storyteller/api";
For shared UI components, import from @storyteller/ui-[componentname]:
import { Button } from "@storyteller/ui-button";
import { Modal } from "@storyteller/ui-modal";
Generating a new component library
# 1. Generate the library
npx nx g @nx/react:library libs/components/toaster --import-path=@storyteller/ui-toaster --bundler=vite
npm install
# 2. Import it somewhere in code
# 3. Sync and build
nx sync
nx build