Files
root 44406b72db Initial commit: img-infinite-canvas AI design workbench MVP
Moteva-style AI design workbench replica. Home prompt creates a project;
the project page provides an infinite canvas with node drag, zoom/pan,
a design chat panel, history replay, image asset upload, and project
save/regenerate.

- Backend: go-zero, DDD layering, sqlc/pgx, optional PostgreSQL; memory
  or Redis cache; asynq job queue; MinIO/S3/R2/OSS object storage;
  sky-valley/pi agent runtime adapter.
- Frontend: Next.js App Router + Vite artifact build, TypeScript, i18n,
  shadcn/ui components, auth (OTP/Turnstile/Google/WeChat).
- Deploy: Docker Compose and k3s manifests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:15:37 +08:00

273 lines
6.1 KiB
Go

package design
import (
"context"
"errors"
"sort"
"strings"
"time"
)
var (
ErrInvalidInput = errors.New("invalid input")
ErrNotFound = errors.New("project not found")
ErrConflict = errors.New("project version conflict")
)
type ProjectStatus string
const (
StatusDraft ProjectStatus = "draft"
StatusExploring ProjectStatus = "exploring"
StatusReady ProjectStatus = "ready"
StatusFailed ProjectStatus = "failed"
)
type NodeType string
const (
NodeTypeBrief NodeType = "brief"
NodeTypeReference NodeType = "reference"
NodeTypeImage NodeType = "image"
NodeTypeText NodeType = "text"
NodeTypeFrame NodeType = "frame"
)
type Viewport struct {
X float64
Y float64
K float64
}
type MockupPoint struct {
X float64 `json:"x"`
Y float64 `json:"y"`
}
type MockupMesh struct {
Columns int `json:"columns"`
Rows int `json:"rows"`
Points []MockupPoint `json:"points"`
}
type MockupPlacement struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Width float64 `json:"width"`
Height float64 `json:"height"`
}
type MockupSurface struct {
TargetID string `json:"targetId"`
Polygon []MockupPoint `json:"polygon"`
Mesh MockupMesh `json:"mesh"`
}
type MockupSurfaceResult struct {
Placement MockupPlacement
Surface MockupSurface
}
type MockupModelMap struct {
DataID string `json:"dataId"`
Width int `json:"width"`
Height int `json:"height"`
URL string `json:"url,omitempty"`
Data []float64 `json:"data,omitempty"`
}
type MockupCameraIntrinsics struct {
Matrix []float64 `json:"matrix"`
}
type MockupModel struct {
Version int `json:"version"`
DepthMap MockupModelMap `json:"depthMap"`
DepthScaleMin float64 `json:"depthScaleMin"`
DepthScaleMax float64 `json:"depthScaleMax"`
ShadeMap MockupModelMap `json:"shadeMap"`
SegmentationMap MockupModelMap `json:"segmentationMap"`
XOffsetMap MockupModelMap `json:"xOffsetMap"`
YOffsetMap MockupModelMap `json:"yOffsetMap"`
CameraIntrinsics MockupCameraIntrinsics `json:"cameraIntrinsics"`
ColorCorrection string `json:"colorCorrection"`
ForegroundImage string `json:"foregroundImage"`
}
type MockupModelResult struct {
Placement MockupPlacement
Model MockupModel
}
type MockupModelAnalysisRequest struct {
Project Project
Node Node
ImageDataURL string
ImageWidth int
ImageHeight int
}
type MockupModelAnalysis struct {
Placement MockupPlacement
Surface MockupSurface
Model MockupModel
}
type MockupBlobData struct {
DataID string
Width int
Height int
Data []byte
CreatedAt time.Time
}
type Node struct {
ID string
Type NodeType
Title string
X float64
Y float64
Width float64
Height float64
Content string
Tone string
Status string
ParentID string
LayerRole string
FontSize float64
FontFamily string
FontWeight string
Color string
TextAlign string
LineHeight float64
LetterSpacing float64
TextDecoration string
TextTransform string
Opacity float64
FillColor string
StrokeColor string
StrokeWidth float64
StrokeStyle string
FlipX bool
FlipY bool
Rotation float64
ImageAdjustments string
MockupSurface MockupSurface
MockupModel MockupModel
MockupSourceContent string
}
type NodeActionRequest struct {
Action string
Prompt string
ImageModel string
ImageSize string
Mask string
Selection string
Options map[string]string
}
type Connection struct {
ID string
FromNodeID string
ToNodeID string
}
type Message struct {
ID string
Role string
Type string
Title string
Content string
ThreadID string
ActionID string
StepID string
ToolCallID string
Name string
ToolHint string
Status string
CreatedAt time.Time
}
type Project struct {
ID string
UserID string
Title string
Brief string
Status ProjectStatus
Thumbnail string
UpdatedAt time.Time
Version string
SnapshotID string
Canvas string
LastThreadID string
Viewport Viewport
Nodes []Node
Connections []Connection
Messages []Message
}
type ProjectSummary struct {
ID string
UserID string
Title string
Brief string
Status ProjectStatus
Thumbnail string
UpdatedAt time.Time
}
type QuickAction struct {
ID string
Label string
Prompt string
Icon string
}
type InspirationItem struct {
ID string
Title string
Category string
Description string
Accent string
}
type Repository interface {
List(ctx context.Context) ([]ProjectSummary, error)
ListPage(ctx context.Context, limit int64, offset int64) ([]ProjectSummary, error)
Get(ctx context.Context, id string) (Project, error)
Save(ctx context.Context, project Project) error
Delete(ctx context.Context, id string) error
}
type CanvasRepository interface {
SaveCanvas(ctx context.Context, project Project, baseVersion string) error
}
type MockupBlobRepository interface {
SaveMockupBlob(ctx context.Context, blob MockupBlobData) error
GetMockupBlob(ctx context.Context, dataID string) (MockupBlobData, error)
}
type MockupModelAnalyzer interface {
AnalyzeMockupModel(ctx context.Context, req MockupModelAnalysisRequest) (MockupModelAnalysis, error)
}
func NormalizeTitle(title string, fallback string) string {
title = strings.TrimSpace(title)
if title == "" {
return fallback
}
return title
}
func NormalizePrompt(prompt string) string {
return strings.TrimSpace(prompt)
}
func SortSummaries(items []ProjectSummary) {
sort.SliceStable(items, func(i, j int) bool {
return items[i].UpdatedAt.After(items[j].UpdatedAt)
})
}