Refactor project name from "Open Claude Design" to "Open Design"

- Updated project name in package.json, package-lock.json, and README files.
- Changed CLI commands and references from "ocd" to "od".
- Adjusted file structure references in documentation and code to reflect new naming conventions.
- Enhanced .gitignore to include new runtime data files.
- Updated metadata in LICENSE file to match new project name.
This commit is contained in:
pftom
2026-04-28 14:48:45 +08:00
parent a98096a042
commit af3f96379a
122 changed files with 952 additions and 474 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ const SECTION_LABEL_KEY: Record<Section, keyof Dict> = {
const SECTION_ORDER: Section[] = ['pages', 'sketches', 'scripts', 'images', 'other'];
/**
* Full-panel browser for a project's `.ocd/projects/<id>/` folder. Mirrors
* Full-panel browser for a project's `.od/projects/<id>/` folder. Mirrors
* Claude Design's "Design Files" surface: grouped sections, hover-revealed
* row menu, drop-files footer, and (when a row is selected) a right-side
* preview pane. Triggered as a sticky first tab in FileWorkspace.
+1 -1
View File
@@ -38,7 +38,7 @@ interface Props {
const SIDEBAR_MIN = 320;
const SIDEBAR_MAX = 560;
const SIDEBAR_DEFAULT = 380;
const SIDEBAR_STORAGE_KEY = 'ocd-entry-sidebar-width';
const SIDEBAR_STORAGE_KEY = 'od-entry-sidebar-width';
function loadSidebarWidth(): number {
try {
+2 -2
View File
@@ -155,7 +155,7 @@ function HtmlViewer({
const data = ev?.data as
| { type?: string; active?: number; count?: number }
| null;
if (!data || data.type !== 'ocd:slide-state') return;
if (!data || data.type !== 'od:slide-state') return;
if (typeof data.active !== 'number' || typeof data.count !== 'number') return;
setSlideState({ active: data.active, count: data.count });
}
@@ -166,7 +166,7 @@ function HtmlViewer({
function postSlide(action: 'next' | 'prev' | 'first' | 'last') {
const win = iframeRef.current?.contentWindow;
if (!win) return;
win.postMessage({ type: 'ocd:slide', action }, '*');
win.postMessage({ type: 'od:slide', action }, '*');
}
// Keyboard nav on the host, so the user can press ←/→ even when focus
+1 -1
View File
@@ -21,7 +21,7 @@ const DICTS: Record<Locale, Dict> = {
'zh-CN': zhCN,
};
const LS_KEY = 'open-claude-design:locale';
const LS_KEY = 'open-design:locale';
// First-run default is English. We honor an explicit user pick saved to
// localStorage but never auto-detect from `navigator.language`, so the
+2 -2
View File
@@ -37,13 +37,13 @@ export const en: Dict = {
'common.daysShort': '{n}d',
'common.untitled': 'Untitled',
'app.brand': 'Open Claude Design',
'app.brand': 'Open Design',
'app.brandPill': 'Research Preview',
'app.brandSubtitle': 'by Nexu Labs',
'app.welcomeLoading': 'Loading workspace…',
'settings.welcomeKicker': 'Welcome',
'settings.welcomeTitle': 'Set up Open Claude Design',
'settings.welcomeTitle': 'Set up Open Design',
'settings.welcomeSubtitle':
"Pick how you'd like to run generations. You can change this any time from the Settings button in the top bar.",
'settings.kicker': 'Settings',
+2 -2
View File
@@ -37,13 +37,13 @@ export const zhCN: Dict = {
'common.daysShort': '{n}天',
'common.untitled': '未命名',
'app.brand': 'Open Claude Design',
'app.brand': 'Open Design',
'app.brandPill': '研究预览版',
'app.brandSubtitle': '由 Nexu Labs 出品',
'app.welcomeLoading': '正在加载工作区…',
'settings.welcomeKicker': '欢迎',
'settings.welcomeTitle': '初始化 Open Claude Design',
'settings.welcomeTitle': '初始化 Open Design',
'settings.welcomeSubtitle':
'选择你希望使用的执行方式。后续可以随时从顶部「设置」按钮中修改。',
'settings.kicker': '设置',
+1 -1
View File
@@ -1,5 +1,5 @@
/* ============================================================
Open Claude Design — visual language modeled on claude.ai/design
Open Design — visual language modeled on claude.ai/design
============================================================ */
:root {
/* Surface palette — warmer paper, hairline borders, soft shadows.
+5 -5
View File
@@ -26,7 +26,7 @@
* Drift fixes baked in:
* - `transform-origin: top left` and the stage is positioned by grid +
* place-items, so scaling never shifts content sideways inside the
* OCD viewer's nested transform wrapper.
* OD viewer's nested transform wrapper.
* - Capture-phase keydown on BOTH window and document so iframe focus
* quirks can't swallow arrow keys.
* - Auto-focus body on load and on every click.
@@ -242,7 +242,7 @@ export const DECK_SKELETON_HTML = `<!doctype html>
// The stage is 1920×1080 and positioned by .deck-shell's
// \`display:grid;place-items:center\`. We scale via transform with
// transform-origin:top-left, then re-center by translating to the
// remainder. This survives nested transforms (e.g. when the OCD viewer
// remainder. This survives nested transforms (e.g. when the OD viewer
// wraps the iframe in its own scale wrapper at zoom != 100%).
function fit() {
var sw = window.innerWidth;
@@ -277,7 +277,7 @@ export const DECK_SKELETON_HTML = `<!doctype html>
else if (e.key === 'Home') { e.preventDefault(); go(0); }
else if (e.key === 'End') { e.preventDefault(); go(slides.length - 1); }
}
// Capture phase + listen on both targets — inside the OCD iframe,
// Capture phase + listen on both targets — inside the OD iframe,
// focus may be on window OR document; a single non-capture listener
// silently misses presses.
window.addEventListener('keydown', onKey, true);
@@ -328,7 +328,7 @@ You may edit only inside slots marked \`SLOT:\`:
These are the failure patterns we just spent days debugging. Each one looks "equivalent" but breaks something specific:
- Don't write your own \`fit()\` function or \`transform: scale()\` script. The framework already does it, and ad-hoc versions drift inside the OCD viewer's nested transform wrapper.
- Don't write your own \`fit()\` function or \`transform: scale()\` script. The framework already does it, and ad-hoc versions drift inside the OD viewer's nested transform wrapper.
- Don't use \`transform-origin: center center\` on the stage. The framework uses \`top left\` plus an explicit translate so scaled content lands at the same place every render.
- Don't use \`document.addEventListener('keydown', )\` alone. Inside an iframe, focus is sometimes on window. The framework adds capture-phase listeners on **both** targets — replacing this with a single listener silently swallows arrow keys.
- Don't replace the localStorage key, the slide-visibility toggle (\`.slide.active\`), or the counter element IDs (\`#deck-cur\`, \`#deck-total\`, \`#deck-prev\`, \`#deck-next\`). The framework reads them by ID.
@@ -338,7 +338,7 @@ These are the failure patterns we just spent days debugging. Each one looks "equ
## Why this matters (so you can judge edge cases)
The framework is a contract with the host viewer. The OCD iframe sits inside a transformed wrapper (the zoom control); the keyboard handler needs capture phase + dual targets; "Share → PDF" reads the print stylesheet; the position survives reloads via localStorage. If a turn rewrites any of these even with "equivalent" code the next turn diverges, and three turns in the deck has subtly broken nav and a one-page PDF. Treat the framework as load-bearing infrastructure.
The framework is a contract with the host viewer. The OD iframe sits inside a transformed wrapper (the zoom control); the keyboard handler needs capture phase + dual targets; "Share → PDF" reads the print stylesheet; the position survives reloads via localStorage. If a turn rewrites any of these even with "equivalent" code the next turn diverges, and three turns in the deck has subtly broken nav and a one-page PDF. Treat the framework as load-bearing infrastructure.
If the user asks for something the framework genuinely doesn't support (vertical decks, custom slide transitions, multi-column simultaneous slides), say so and ask before forking. **Default answer: keep the framework, change the slide content.**
+2 -2
View File
@@ -2,7 +2,7 @@
* Discovery + planning + huashu-philosophy directives.
*
* This is the dominant layer of the composed system prompt. It stacks
* BEFORE the official OCD designer prompt so the hard rules below emit
* BEFORE the official OD designer prompt so the hard rules below emit
* a discovery form on turn 1, branch into a direction picker / brand
* extraction on turn 2, plan with TodoWrite on turn 3 beat the softer
* "skip questions for small tweaks" wording in the base prompt.
@@ -23,7 +23,7 @@
*/
import { renderDirectionFormBody, renderDirectionSpecBlock } from './directions';
export const DISCOVERY_AND_PHILOSOPHY = `# OCD core directives (read first — these override anything later in this prompt)
export const DISCOVERY_AND_PHILOSOPHY = `# OD core directives (read first — these override anything later in this prompt)
You are an expert designer working with the user as your manager. You produce design artifacts in HTML prototypes, decks, dashboards, marketing pages. **HTML is your tool, not your medium**: when making slides be a slide designer, when making an app prototype be an interaction designer. Don't write a web page when the brief is a deck.
+2 -2
View File
@@ -1,8 +1,8 @@
/**
* The base system prompt for Open Claude Design.
* The base system prompt for Open Design.
*
* Adapted from claude.ai/design's "expert designer" prompt same identity,
* workflow, and content philosophy, retargeted to the tools an OCD-managed
* workflow, and content philosophy, retargeted to the tools an OD-managed
* agent actually has (Claude Code's Read / Edit / Write / Bash / Glob / Grep
* / TodoWrite, plus the project folder as cwd).
*
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Prompt composer. The base is the OCD-adapted "expert designer" system
* Prompt composer. The base is the OD-adapted "expert designer" system
* prompt (see ./official-system.ts) a full identity, workflow, and
* content-philosophy charter. Stacked on top:
*
+1 -1
View File
@@ -80,7 +80,7 @@ export async function fetchSkillExample(id: string): Promise<string | null> {
}
}
// Project files — all paths are scoped under .ocd/projects/<id>/ on disk.
// Project files — all paths are scoped under .od/projects/<id>/ on disk.
export async function fetchProjectFiles(projectId: string): Promise<ProjectFile[]> {
try {
+1 -1
View File
@@ -44,7 +44,7 @@ export function exportAsZip(html: string, title: string): void {
{ path: `${slug}/index.html`, content: doc },
{
path: `${slug}/README.md`,
content: `# ${title || slug}\n\nGenerated by Open Claude Design.\nOpen index.html in a browser to view.\n`,
content: `# ${title || slug}\n\nGenerated by Open Design.\nOpen index.html in a browser to view.\n`,
},
]);
triggerDownload(blob, `${slug}.zip`);
+4 -4
View File
@@ -9,9 +9,9 @@
* When `options.deck` is set we also inject a `postMessage` listener that
* lets the host advance / rewind slides without relying on the iframe
* having keyboard focus. The host posts:
* { type: 'ocd:slide', action: 'next' | 'prev' | 'first' | 'last' | 'go', index?: number }
* { type: 'od:slide', action: 'next' | 'prev' | 'first' | 'last' | 'go', index?: number }
* and the iframe responds with:
* { type: 'ocd:slide-state', active: number, count: number }
* { type: 'od:slide-state', active: number, count: number }
* after every navigation so the host can render its own counter / dots.
*/
export function buildSrcdoc(
@@ -55,7 +55,7 @@ function injectDeckBridge(doc: string): string {
try {
var list = slides();
window.parent.postMessage({
type: 'ocd:slide-state',
type: 'od:slide-state',
active: activeIndex(),
count: list.length,
}, '*');
@@ -63,7 +63,7 @@ function injectDeckBridge(doc: string): string {
}
window.addEventListener('message', function(ev){
var data = ev && ev.data;
if (!data || data.type !== 'ocd:slide') return;
if (!data || data.type !== 'od:slide') return;
var list = slides();
var i = activeIndex();
if (data.action === 'next') go(i + 1);
+1 -1
View File
@@ -1,6 +1,6 @@
import type { AppConfig } from '../types';
const STORAGE_KEY = 'open-claude-design:config';
const STORAGE_KEY = 'open-design:config';
export const DEFAULT_CONFIG: AppConfig = {
mode: 'daemon',
+1 -1
View File
@@ -86,7 +86,7 @@ export interface SkillSummary {
upstream: string | null;
/** Lower number = higher priority in the Examples gallery. `null` keeps
* the skill in its natural alphabetical position below all featured
* entries. Set via `ocd.featured` in the SKILL.md frontmatter. */
* entries. Set via `od.featured` in the SKILL.md frontmatter. */
featured?: number | null;
hasBody: boolean;
examplePrompt: string;