一键导入
canvas-types
Foundational Canvas type definitions and language support patterns. Use when working with Canvas types, schemas, or language configuration.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Foundational Canvas type definitions and language support patterns. Use when working with Canvas types, schemas, or language configuration.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Creates Next.js 16 API routes with auth, validation, and tenant scoping. Use when creating API endpoints.
Implements AI tools for Canvas generation and updates. Use when creating GenUI tools for code generation, document editing, or Canvas interactions.
Develops Canvas code execution features with Pyodide/iframe sandboxing. Use when working on Python/JS execution, package management, or sandbox security.
Creates and extends Canvas UI components with Monaco editor, split views, and educational context. Use when building Canvas panel, editor, or preview features.
Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. When Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks
Creates educational UI components following learning science principles. Use for classroom, student, or teacher interfaces.
| name | canvas-types |
| description | Foundational Canvas type definitions and language support patterns. Use when working with Canvas types, schemas, or language configuration. |
| allowed-tools | Read, Write, Edit, Glob |
| context | fork |
Use this skill when:
// From lib/canvas/types.ts
export const CANVAS_TYPES = [
'code', // Executable code with Monaco editor
'document', // Markdown/rich text editor
'visualization', // D3/Chart.js interactive visualizations
'quiz', // Interactive assessment
'flashcards', // Study cards with flip interaction
'diagram', // Mermaid/PlantUML diagrams
'math', // LaTeX mathematical expressions
'react', // React component preview
] as const;
export type CanvasType = (typeof CANVAS_TYPES)[number];
export type ViewMode = 'code' | 'preview' | 'split';
export interface CanvasState {
// Core state
isOpen: boolean;
content: string;
type: CanvasType;
title: string;
language: string;
viewMode: ViewMode;
// History for undo/redo
history: string[];
historyIndex: number;
// Generation state
generationPrompt: string;
isGenerating: boolean;
}
import { z } from 'zod';
export const CanvasConfigSchema = z.object({
type: z.enum(CANVAS_TYPES),
title: z.string().max(100),
language: z.string().optional(),
initialContent: z.string().optional().default(''),
generationPrompt: z.string().optional(),
educationalContext: z.object({
topic: z.string().optional(),
difficulty: z.enum(['beginner', 'intermediate', 'advanced']).optional(),
learningObjective: z.string().optional(),
}).optional(),
// Artifact persistence tracking
artifactId: z.string().uuid().optional(),
conversationId: z.string().uuid().optional(),
messageId: z.string().uuid().optional(),
toolInvocationId: z.string().optional(),
});
export type CanvasConfig = z.infer<typeof CanvasConfigSchema>;
/**
* Maximum canvas content size (1MB)
* Prevents memory abuse while allowing substantial code examples
*/
export const CANVAS_MAX_CONTENT_SIZE = 1_048_576;
export const CanvasContentSchema = z.object({
type: z.enum(CANVAS_TYPES),
title: z.string().max(100),
content: z.string().max(CANVAS_MAX_CONTENT_SIZE),
language: z.string().optional(),
metadata: z.object({
educationalObjective: z.string().optional(),
difficulty: z.enum(['beginner', 'intermediate', 'advanced']).optional(),
estimatedTime: z.number().optional(),
prerequisites: z.array(z.string()).optional(),
}).optional(),
});
export type CanvasContent = z.infer<typeof CanvasContentSchema>;
export const SUPPORTED_LANGUAGES = {
// P0 - Must have (curriculum analysis)
tier1: [
{ id: 'python', name: 'Python', extensions: ['.py'], monacoId: 'python' },
{ id: 'javascript', name: 'JavaScript', extensions: ['.js'], monacoId: 'javascript' },
{ id: 'html', name: 'HTML', extensions: ['.html'], monacoId: 'html' },
{ id: 'css', name: 'CSS', extensions: ['.css'], monacoId: 'css' },
{ id: 'sql', name: 'SQL', extensions: ['.sql'], monacoId: 'sql' },
{ id: 'markdown', name: 'Markdown', extensions: ['.md'], monacoId: 'markdown' },
],
// P1 - High priority
tier2: [
{ id: 'typescript', name: 'TypeScript', extensions: ['.ts', '.tsx'], monacoId: 'typescript' },
{ id: 'java', name: 'Java', extensions: ['.java'], monacoId: 'java' },
{ id: 'r', name: 'R', extensions: ['.r'], monacoId: 'r' },
{ id: 'latex', name: 'LaTeX', extensions: ['.tex'], monacoId: 'latex' },
],
// P2 - Secondary
tier3: [
{ id: 'c', name: 'C', extensions: ['.c', '.h'], monacoId: 'c' },
{ id: 'cpp', name: 'C++', extensions: ['.cpp', '.hpp'], monacoId: 'cpp' },
],
} as const;
export const EXECUTION_SUPPORT: Record<string, 'pyodide' | 'iframe' | 'none'> = {
python: 'pyodide',
javascript: 'iframe',
html: 'iframe',
typescript: 'iframe', // Transpiled to JS
react: 'iframe',
css: 'iframe',
sql: 'none',
java: 'none',
c: 'none',
cpp: 'none',
r: 'none',
latex: 'none',
markdown: 'none',
mermaid: 'none',
};
export function getDefaultLanguage(type: CanvasType): string {
const defaults: Record<CanvasType, string> = {
code: 'python',
visualization: 'html',
react: 'typescript',
document: 'markdown',
diagram: 'mermaid',
math: 'latex',
quiz: 'json',
flashcards: 'json',
};
return defaults[type] || 'plaintext';
}
export function getMonacoLanguage(language: string): string {
const mapping: Record<string, string> = {
python: 'python',
javascript: 'javascript',
typescript: 'typescript',
tsx: 'typescript',
jsx: 'javascript',
html: 'html',
css: 'css',
markdown: 'markdown',
json: 'json',
sql: 'sql',
java: 'java',
c: 'c',
cpp: 'cpp',
csharp: 'csharp',
go: 'go',
rust: 'rust',
latex: 'latex',
mermaid: 'markdown', // No native mermaid support
};
return mapping[language] || 'plaintext';
}
export function canExecute(language: string): boolean {
return (
EXECUTION_SUPPORT[language] !== 'none' &&
EXECUTION_SUPPORT[language] !== undefined
);
}
export function getFileExtension(language: string): string {
const extensions: Record<string, string> = {
python: '.py',
javascript: '.js',
typescript: '.ts',
html: '.html',
css: '.css',
markdown: '.md',
json: '.json',
sql: '.sql',
java: '.java',
c: '.c',
cpp: '.cpp',
};
return extensions[language] || '.txt';
}
export interface OpenCanvasResult {
action: 'open_canvas';
canvasConfig: {
type: CanvasType;
title: string;
language: string;
initialContent: string;
generationPrompt: string;
educationalContext?: {
topic?: string;
difficulty?: 'beginner' | 'intermediate' | 'advanced';
learningObjective?: string;
};
};
}
export interface UpdateCanvasResult {
action: 'update_canvas';
updates: {
content?: string;
title?: string;
language?: string;
};
}
// In types.ts
export const CANVAS_TYPES = [
// ... existing
'new_type', // Add here
] as const;
// In getDefaultLanguage()
const defaults: Record<CanvasType, string> = {
// ... existing
new_type: 'json', // Add default
};
// In genui renderer
switch (canvasType) {
// ... existing cases
case 'new_type':
return <NewTypeCanvas {...props} />;
}
// In SUPPORTED_LANGUAGES
tier2: [
// ... existing
{ id: 'rust', name: 'Rust', extensions: ['.rs'], monacoId: 'rust' },
],
// In EXECUTION_SUPPORT
rust: 'none', // Or 'iframe' if you implement WASM execution
// In getMonacoLanguage()
rust: 'rust',
// In getFileExtension()
rust: '.rs',
export function isCanvasType(value: unknown): value is CanvasType {
return typeof value === 'string' && CANVAS_TYPES.includes(value as CanvasType);
}
export function supportsExecution(language: string): language is 'python' | 'javascript' | 'typescript' | 'html' | 'react' | 'css' {
return EXECUTION_SUPPORT[language] !== 'none' && EXECUTION_SUPPORT[language] !== undefined;
}
import { CanvasConfigSchema } from '@/lib/canvas/types';
function parseCanvasConfig(input: unknown) {
const result = CanvasConfigSchema.safeParse(input);
if (!result.success) {
console.error('Invalid canvas config:', result.error.errors);
return null;
}
return result.data;
}
function isContentValid(content: string): boolean {
const byteSize = new TextEncoder().encode(content).length;
return byteSize <= CANVAS_MAX_CONTENT_SIZE;
}