Initial import: open-design source for helix-mind.ai distribution
Some checks failed
ci / Validate workspace (push) Successful in 12m32s
landing-page-ci / Validate landing page (push) Successful in 9m41s
landing-page-deploy / Deploy landing page (push) Failing after 5m23s
github-metrics / Generate repository metrics SVG (push) Failing after 2m6s
refresh-contributors-wall / Refresh contributors wall cache bust (push) Failing after 12s

This repository contains the open-design daemon CLI source code, built
and packaged at https://helix-mind.ai/cli/open-design/latest.tgz for use
by the HelixMind /design slash command.

Licenses: Apache-2.0 (root) + MIT (skills/*)
This commit is contained in:
marco
2026-05-06 20:50:24 +02:00
commit 5dd70b5016
1336 changed files with 287186 additions and 0 deletions

View File

@@ -0,0 +1,158 @@
import { useEffect, useState, type CSSProperties } from 'react';
import type { PetAtlasRowDef } from '../../types';
import type { ResolvedPet } from './pets';
interface Props {
active: ResolvedPet;
className?: string;
// Optional explicit pixel size; the overlay leaves it unset and
// inherits container metrics, while the rail / settings preview
// pin a concrete size to keep the cell shape consistent.
size?: number;
// Atlas-mode only — which row id (e.g. `idle`, `waving`, `running-right`)
// to play right now. Defaults to `idle` (or the first row, when the
// atlas does not declare an idle row). Ignored for emoji / strip pets.
rowId?: string;
}
// Renders the pet's face. Four cases:
//
// 1. No imageUrl — just the emoji glyph (legacy / built-ins).
// 2. imageUrl + atlas — the full Codex 8x9 sprite atlas. We pick the
// requested row by index and step through that row's frames at
// the row's per-second fps. Mirrors the `codex-pets-react`
// `SpriteAnimator` behaviour so different interactions (idle,
// waving, running-*) play the right row of the atlas.
// 3. imageUrl + frames > 1 — legacy horizontal spritesheet (one row
// cropped out). Walked through with a CSS `steps()` animation.
// 4. imageUrl + frames === 1 — single static image.
export function PetSpriteFace({ active, className, size, rowId }: Props) {
if (!active.imageUrl) {
const style: CSSProperties | undefined = size
? { fontSize: Math.round(size * 0.85), width: size, height: size, lineHeight: 1 }
: undefined;
return (
<span className={className} aria-hidden style={style}>
{active.glyph}
</span>
);
}
if (active.atlas && active.atlas.rowsDef.length > 0) {
return (
<AtlasSprite
imageUrl={active.imageUrl}
cols={Math.max(1, active.atlas.cols)}
rows={Math.max(1, active.atlas.rows)}
rowsDef={active.atlas.rowsDef}
rowId={rowId}
className={className}
size={size}
/>
);
}
const frames = Math.max(1, active.frames ?? 1);
const fps = Math.max(1, active.fps ?? 6);
if (frames === 1) {
return (
<span
className={`${className ?? ''} pet-image static`.trim()}
aria-hidden
style={{
backgroundImage: `url(${active.imageUrl})`,
width: size,
height: size,
}}
/>
);
}
// Strip mode — N frames laid out horizontally. The image is
// (N × container_width) wide, so the visible frame is selected by
// sliding background-position-x from 0% to 100% in (N-1) steps.
// `steps(N, jump-none)` is required because the default jump-end
// would land on 0/N, 1/N, …, (N-1)/N, which slices each frame mid-cell;
// jump-none lands on the actual cell boundaries 0/(N-1) … 1.
const durationMs = Math.round((frames / fps) * 1000);
return (
<span
className={`${className ?? ''} pet-image frames`.trim()}
aria-hidden
style={{
backgroundImage: `url(${active.imageUrl})`,
backgroundSize: `${frames * 100}% 100%`,
animation: `pet-frames ${durationMs}ms steps(${frames}, jump-none) infinite`,
width: size,
height: size,
}}
/>
);
}
interface AtlasSpriteProps {
imageUrl: string;
cols: number;
rows: number;
rowsDef: PetAtlasRowDef[];
rowId?: string;
className?: string;
size?: number;
}
// Atlas renderer. Drives the frame index from JS instead of a CSS
// `steps()` animation — sidesteps the jump-end vs jump-none footgun
// and makes per-row fps trivial to swap when the parent flips the
// `rowId` prop (idle ↔ waving ↔ running-*).
function AtlasSprite({
imageUrl,
cols,
rows,
rowsDef,
rowId,
className,
size,
}: AtlasSpriteProps) {
const def =
rowsDef.find((r) => r.id === rowId)
?? rowsDef.find((r) => r.id === 'idle')
?? rowsDef[0]!;
const rowFrames = Math.max(1, def.frames);
const fps = Math.max(1, def.fps);
const [frame, setFrame] = useState(0);
// Reset to frame 0 on row change so a freshly-triggered animation
// (e.g. tap → waving) starts cleanly instead of mid-cycle.
useEffect(() => {
setFrame(0);
if (rowFrames <= 1) return;
const intervalMs = Math.max(16, Math.round(1000 / fps));
const id = window.setInterval(() => {
setFrame((f) => (f + 1) % rowFrames);
}, intervalMs);
return () => window.clearInterval(id);
}, [def.id, def.index, rowFrames, fps]);
// Background math:
// - background-size = (cols × 100%) × (rows × 100%)
// → each grid cell renders at exactly the container size.
// - background-position-x = frame / (cols - 1) × 100%
// → 0% slides to the leftmost cell, 100% to the rightmost,
// intermediate cells land at frame/(cols-1) of the offset range.
// - background-position-y = rowIndex / (rows - 1) × 100%
const xPct = cols > 1 ? (frame / (cols - 1)) * 100 : 0;
const yPct = rows > 1 ? (def.index / (rows - 1)) * 100 : 0;
return (
<span
className={`${className ?? ''} pet-image atlas`.trim()}
aria-hidden
style={{
backgroundImage: `url(${imageUrl})`,
backgroundSize: `${cols * 100}% ${rows * 100}%`,
backgroundPosition: `${xPct}% ${yPct}%`,
width: size,
height: size,
}}
/>
);
}