Tutorial 1 - Blank Template
Create your first CyanPrint template from scratch
Tutorial 1: Blank Template
Create a minimal working template from scratch and test it with cyanprint try.
Prerequisites
- Docker installed and running
- CyanPrint CLI installed
- Choose one runtime:
- TypeScript: Node.js 18+ and Bun
- Python: Python 3.11+ and pip
- C#: .NET 8 SDK
Create project structure
mkdir my-first-template && cd my-first-templatemkdir -p cyan templatesecho "# My Project" > templates/README.md
Create cyan.yaml
cyan.yaml
username: myusername: my-first-templatedescription: My first CyanPrint templatebuild:registry: docker.ioimages:blob:image: myuser/my-first-template-blobdockerfile: cyan/Dockerfiletemplate:image: myuser/my-first-templatedockerfile: cyan/template.Dockerfile
Create template logic
Create cyan/index.ts:
cyan/index.ts
import { startTemplateWithFn, GlobType } from '@atomicloud/cyan-sdk';startTemplateWithFn(async (i, d) => {const name = await i.text('What is your project name?', 'myuser/my-first-template/name');return {processors: [{name: 'cyan/default',files: [{ root: 'templates', glob: '**/*', exclude: [], type: GlobType.Copy }],config: { vars: { name } }}]};});
Create cyan/package.json:
cyan/package.json
{"name": "my-first-template","type": "module","dependencies": {"@atomicloud/cyan-sdk": "latest"}}
Create cyan/Dockerfile and cyan/template.Dockerfile:
cyan/Dockerfile
FROM oven/bun:1.1.31WORKDIR /appLABEL cyanprint.dev=trueCOPY package.json bun.lockb* ./RUN bun installCOPY . .CMD ["bun", "run", "index.ts"]
Install dependencies:
cd cyan && bun install && cd ..
Create cyan/index.py:
cyan/index.py
from cyanprintsdk import start_template_with_fn, GlobTypefrom cyanprintsdk.domain.core.cyan import Cyan, CyanProcessor, CyanGlobasync def my_template(i, d):name = await i.text("What is your project name?", "myuser/my-first-template/name")return Cyan(processors=[CyanProcessor(name="cyan/default",files=[CyanGlob(root="templates", glob="**/*", exclude=[], type=GlobType.Copy)],config={"vars": {"name": name}})])start_template_with_fn(my_template)
Create cyan/requirements.txt:
cyan/requirements.txt
cyanprintsdk>=1.0.0
Create cyan/Dockerfile and cyan/template.Dockerfile:
cyan/Dockerfile
FROM python:3.11-slimWORKDIR /appLABEL cyanprint.dev=trueCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txtCOPY . .CMD ["python", "index.py"]
Install dependencies:
cd cyan && pip install -r requirements.txt && cd ..
Create cyan/Program.cs:
cyan/Program.cs
using sulfone_helium;using sulfone_helium.Domain.Core;CyanEngine.StartTemplate(args, async (i, d) =>{var name = await i.Text("What is your project name?", "myuser/my-first-template/name");return new Cyan{Processors =[new CyanProcessor{Name = "cyan/default",Files =[new CyanGlob{Root = "templates",Glob = "**/*",Exclude = [],Type = GlobType.Copy}],Config = new { vars = new { name } }}]};});
Create cyan/my-first-template.csproj:
cyan/my-first-template.csproj
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable></PropertyGroup><ItemGroup><PackageReference Include="AtomiCloud.CyanPrint" Version="*" /></ItemGroup></Project>
Create cyan/Dockerfile and cyan/template.Dockerfile:
cyan/Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0WORKDIR /appLABEL cyanprint.dev=trueCOPY *.csproj .RUN dotnet restoreCOPY . .CMD ["dotnet", "run"]
Install dependencies:
cd cyan && dotnet restore && cd ..
Test your template
cyanprint try template . ./test-output
This builds the Docker image, starts the coordinator, prompts for your questions, and generates the project.
Check the output:
cat ./test-output/README.md
Project Structure
cyan.yaml
index.ts
package.json
Dockerfile
template.Dockerfile
README.md
Key Concepts
| Part | Description |
|---|---|
startTemplateWithFn | Entry point - starts template server on port 5550 |
i | Inquirer - ask user questions (text, select, etc.) |
d | Determinism - access deterministic values |
processors | List of file processors to run |
| Part | Description |
|---|---|
start_template_with_fn | Entry point - starts template server on port 5550 |
i | Inquirer - ask user questions (text, select, etc.) |
d | Determinism - access deterministic values |
processors | List of file processors to run |
| Part | Description |
|---|---|
CyanEngine.StartTemplate | Entry point - starts template server on port 5550 |
i | Inquirer - ask user questions (Text, Select, etc.) |
d | Determinism - access deterministic values |
Processors | List of file processors to run |
GlobType.Copy copies files without variable substitution—perfect for static files.
Next Steps
- Tutorial 2: Adding Variables - Learn variable substitution
- Automated Testing - Set up snapshot tests