Your first template
This walkthrough takes you from an empty directory to a template zip that the Port60 Studio can accept. You do not need the Port60 platform repository or a platform account to build and validate the template locally.
Prerequisites
Section titled “Prerequisites”- Node 20 or newer
- npm
Templates contain Liquid and CSS only. The kit supplies the preview renderer, contract fixtures and the same conformance checks used when you upload a template.
1. Create the template
Section titled “1. Create the template”Run the published kit with npx:
npx @port60/template-kit@latest create my-templatecd my-templatenpm installThe folder name becomes the template’s name, and the label derives from it, pass --name or
--label only when the identity should differ from the folder (the name is your immutable
catalogue identity, name@version, in the store and marketplace). The scaffold pins the kit you
scaffolded with as a devDependency, so npm install puts you on the current contract tooling. The scaffold
includes npm scripts plus AGENTS.md and CLAUDE.md, so a coding agent receives the same rules as a
human contributor.
Your new project contains:
my-template/├── manifest.json├── layout.liquid├── sections/├── assets/│ └── theme.css├── AGENTS.md└── package.jsonmanifest.json is the template’s identity and capability declaration. Keep name lowercase and
hyphenated. Change label and description to the wording a non profit will see in the picker.
2. Preview it
Section titled “2. Preview it”npm run devOpen http://localhost:4400. The preview renders the contract’s sample
content, including a worship schedule when the template declares supports.worship. Functional
islands appear as realistic, non-interactive skeletons using their published styling classes.
Payments, identity, consent and other live behaviour remain platform owned, and the preview makes
no network requests.
Files are read again on refresh. Keep the preview open while you edit layout.liquid,
sections/*.liquid and assets/theme.css.
3. Make the design yours
Section titled “3. Make the design yours”Most of the design lives in two places:
assets/theme.csscontrols colour, typography, spacing, responsive layout and the documented styling classes for platform islands.sections/*.liquidcontrols the markup for each supported section type.
Keep outputs escaped. Use | raw only for a contract field documented as sanitised rich text:
<section class="page-hero"> {% if section.eyebrow %}<p>{{ section.eyebrow }}</p>{% endif %} <h1>{{ section.title }}</h1> {% if section.bodyHtml %} <div>{{ section.bodyHtml | raw }}</div> {% endif %}</section>Navigation, worship times, donations and sign in are all supplied by the platform. Render their documented data or place their islands. Do not replace them with fixed sample content.
4. Validate it
Section titled “4. Validate it”npm run validate:jsonThe command checks the manifest, restricted Liquid dialect, minimal and sample fixtures, island declarations, layout slot and capability claims. A successful result includes the capabilities the validator has proven:
{ "ok": true, "errors": [], "warnings": [], "provenSupports": { "layout": true, "worship": true }}Treat every error as an upload blocker. Review warnings too, particularly a missing
member_menu, because member enabled sites would otherwise lose their sign in route.
5. Package and upload it
Section titled “5. Package and upload it”npm run packageThe kit validates once more and creates <name>-<version>.zip with only the allowed artifact
files. Upload that zip in your Studio, open the template, choose Versions, then submit the
validated version for review.
Published versions are immutable. Increase the semantic version in manifest.json before you
package the next release. Existing sites stay on their pinned version until they deliberately
apply an update.

