CJ Code portfolio site for agencies and companies: website design, redesign, updates and maintenance, AI automation, chatbots, and workflow integration.
Static HTML/CSS/JS. No build step.
The embeddable booking product lives in booking/. It is a Next.js + PostgreSQL multi-tenant app: businesses configure services and hours, paste a snippet, and visitors book on their site.
cd booking
cp .env.example .env
npm install
npm run db:setup
npm run devSee booking/README.md for environment variables, the demo tenant ([email protected] / DemoPass123!), and embed instructions. Host it on Render with booking/docs/render-deploy.md. To put the widget on a client GitHub Pages site, use booking/docs/github-pages-install.md.
- Open
index.htmlin a browser (double-click, or drag it into Chrome/Edge). - Optional, from this folder:
npx --yes serve .Then visit the URL it prints (usually http://localhost:3000).
Work cards render from js/projects.js. Empty slots stay as ghost cards until you fill them (three slots total).
Add objects to window.PROJECTS:
window.PROJECTS = [
{
title: "Northline agency site rebuild",
client: "Northline",
category: "Redesign",
summary: "Rebuilt the marketing site and wired a qualifier chatbot into intake.",
tags: ["Redesign", "Chatbot"],
image: "images/northline.jpg",
video: "media/demo.mp4",
href: "https://example.com",
},
];| Field | Required | Notes |
|---|---|---|
title |
yes | Card heading |
client |
no | Shown under the title |
category |
no | Small label (Design, Redesign, Automation, …) |
summary |
no | One or two sentences |
tags |
no | Array of short labels |
image |
no | Path relative to this folder (put files in images/) |
video |
no | Path to an mp4 (e.g. media/demo-assistant.mp4). Plays muted, looping. Prefer over image when both are set |
demo |
no | "email-assistant" or "intake-qualifier" — opens a gated sample walkthrough |
href |
no | Makes the card a link. Use "#" or omit for an unlinked card |
Refresh the browser after you save. No rebuild.
The included demo video (media/willow-grove-chatbot-v5.mp4) shows a chatbot on a fictional client site (Willow & Grove). Regenerate it with:
python scripts/make_demo_video.pyThen copy or rename the output if you want a cache-busting filename.
contact.html has a booking calendar that runs on this static site. The live host is Cloudflare Workers (www.cjcode.workers.dev). Visitors pick a time, choose Web / Automation / Web and Automation, and can add extra information. Confirm opens an email draft to booking.notifyEmail — no login, no localhost, no extra server.
Hours, need options, timezone, and the notify address are in js/config.js under booking.
booking: {
timezone: "America/Chicago",
timezoneLabel: "Central Time",
notifyEmail: "[email protected]",
needs: [ /* Web, Automation, Web and Automation */ ],
hours: [ /* Mon–Thu 1:00–3:00pm Central; Friday closed */ ],
blockedDates: [ /* optional YYYY-MM-DD closed days */ ],
}The Booklane app in booking/ is a separate multi-tenant product. The portfolio contact page does not load it.
The corner widget is the CJ Code assistant. It answers from js/faq.js — the same services, starting prices, payment terms, and booking path as the site. Keep that file in sync when copy changes. Do not add prices or promises that are not already on the pages.
On Cloudflare, the widget POSTs to /api/chat. worker.js tries Workers AI (AI binding, model @cf/meta/llama-3.1-8b-instruct) using retrieved FAQ snippets only. If the binding is missing, the model call fails, or you are serving the files locally, the widget still answers from the FAQ in the browser. Off-topic questions get an “I’m not sure” plus Book a call — it will not invent numbers.
No API key belongs in the frontend. The only wiring is the Workers AI binding already in wrangler.jsonc:
Enable Workers AI on the Cloudflare account that deploys cjcode. There is no secret name to set. If Workers AI is not enabled, deploy still serves the site; chat falls back to FAQ retrieval.
Click Try Demo on a work card. Both tools are walkthroughs, not free products:
- Sample inputs only (no pasting a real customer email or a real project request)
- Two generates per demo, per browser
- Output is marked as a demo sample
- No copy button for a sendable reply or a usable client brief
Change the generate cap in js/config.js (demoMaxUses). Do not put an API key in the frontend.
The live site is https://www.cjcode.workers.dev (Git-connected Worker cjcode). Pushes to master deploy it. Dashboard Create app: deploy command npx wrangler deploy, build command empty. Chat uses the AI binding in wrangler.jsonc when Workers AI is enabled on the account.
Book a call: https://www.cjcode.workers.dev/contact.html