From 96304b9d4e9fa1e7821885bf6dc2e51c72be0aee Mon Sep 17 00:00:00 2001
From: Vineeth Voruganti <13438633+VVoruganti@users.noreply.github.com>
Date: Fri, 22 Aug 2025 13:09:57 -0400
Subject: [PATCH] feat: Plugin for dynamically generated opengraph images
(#108)
---
.cursor/rules/component-development.mdc | 149 +++++++++
.cursor/rules/content-authoring.mdc | 79 +++++
.cursor/rules/project-structure.mdc | 50 ++++
.cursor/rules/quartz-configuration.mdc | 185 ++++++++++++
.cursor/rules/styling-conventions.mdc | 219 ++++++++++++++
content/careers/Founding ML Engineer.md | 75 -----
quartz.config.ts | 283 +++++++++---------
quartz/components/Head.tsx | 19 +-
quartz/plugins/transformers/index.ts | 1 +
quartz/plugins/transformers/opengraphImage.ts | 99 ++++++
static/og-image.png | Bin 0 -> 30658 bytes
11 files changed, 946 insertions(+), 213 deletions(-)
create mode 100644 .cursor/rules/component-development.mdc
create mode 100644 .cursor/rules/content-authoring.mdc
create mode 100644 .cursor/rules/project-structure.mdc
create mode 100644 .cursor/rules/quartz-configuration.mdc
create mode 100644 .cursor/rules/styling-conventions.mdc
delete mode 100644 content/careers/Founding ML Engineer.md
create mode 100644 quartz/plugins/transformers/opengraphImage.ts
create mode 100644 static/og-image.png
diff --git a/.cursor/rules/component-development.mdc b/.cursor/rules/component-development.mdc
new file mode 100644
index 000000000..53d8f912c
--- /dev/null
+++ b/.cursor/rules/component-development.mdc
@@ -0,0 +1,149 @@
+---
+globs: *.ts,*.tsx
+description: Development guidelines for React/TypeScript components in the Quartz framework
+---
+
+# Component Development Guidelines
+
+## Quartz Component Architecture
+Quartz uses Preact (React-compatible) for components. All UI components live in [quartz/components/](mdc:quartz/components/).
+
+### Component Types
+1. **Page Components** (`quartz/components/pages/`) - Full page layouts
+2. **UI Components** (`quartz/components/`) - Reusable interface elements
+3. **Script Components** (`quartz/components/scripts/`) - Client-side functionality
+
+### Component Structure
+Every Quartz component should follow this pattern:
+
+```typescript
+import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
+
+const ComponentName: QuartzComponent = ({
+ fileData,
+ cfg,
+ tree,
+ displayClass
+}: QuartzComponentProps) => {
+ // Component logic here
+ return
+ {/* JSX content */}
+
+}
+
+// Optional: Add CSS if needed
+ComponentName.css = "component-name.scss"
+
+// Export as constructor
+export default (() => ComponentName) satisfies QuartzComponentConstructor
+```
+
+## TypeScript Conventions
+
+### Type Safety
+- Always use proper TypeScript types, never `any`
+- Import types from [quartz/components/types.ts](mdc:quartz/components/types.ts)
+- Use `QuartzComponentProps` for component props
+- For utility functions, import from [quartz/util/](mdc:quartz/util/)
+
+### Required Imports
+```typescript
+import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
+```
+
+### File Data Access
+Components receive file metadata through `fileData`:
+```typescript
+const title = fileData.frontmatter?.title
+const slug = fileData.slug
+const content = fileData.description
+```
+
+## Component Patterns
+
+### Conditional Rendering
+```typescript
+if (!fileData.frontmatter?.title) {
+ return null
+}
+```
+
+### CSS Classes
+- Use `displayClass` prop for responsive visibility
+- Add component-specific classes with BEM methodology
+- SCSS files should be named to match component
+
+### Client-Side Scripts
+For interactive components, create accompanying scripts in `quartz/components/scripts/`:
+```typescript
+// In script file
+document.addEventListener("nav", () => {
+ // Re-initialize after page navigation
+})
+```
+
+## Component Registration
+
+### In quartz.layout.ts
+Add new components to the appropriate layout section:
+```typescript
+export const defaultContentPageLayout: PageLayout = {
+ beforeBody: [
+ Component.Breadcrumbs(),
+ Component.ArticleTitle(),
+ Component.ContentMeta(),
+ Component.TagList(),
+ ],
+ left: [
+ Component.PageTitle(),
+ Component.MobileOnly(Component.Spacer()),
+ Component.Search(),
+ Component.Darkmode(),
+ Component.DesktopOnly(Component.Explorer()),
+ ],
+ right: [
+ Component.Graph(),
+ Component.DesktopOnly(Component.TableOfContents()),
+ Component.Backlinks(),
+ ],
+}
+```
+
+### Component Exports
+All components must be exported in [quartz/components/index.ts](mdc:quartz/components/index.ts):
+```typescript
+export { default as YourComponent } from "./YourComponent"
+```
+
+## Best Practices
+
+### Performance
+- Use functional components (avoid class components)
+- Minimize DOM manipulation; prefer declarative JSX
+- For heavy computations, consider memoization
+
+### Accessibility
+- Use semantic HTML elements
+- Include proper ARIA labels where needed
+- Ensure keyboard navigation works
+
+### Responsive Design
+- Use `displayClass` for responsive hiding/showing
+- Test components at different screen sizes
+- Consider mobile-first design approach
+
+### Error Handling
+- Handle missing data gracefully
+- Provide fallbacks for optional frontmatter fields
+- Use optional chaining: `fileData.frontmatter?.field`
+
+## Debugging
+- Use `console.log` sparingly; prefer TypeScript for catching errors
+- Test component isolation by temporarily removing from layout
+- Check browser dev tools for client-side script errors
+
+## Integration with Plugins
+Components often work with Quartz plugins:
+- Transformers modify content before components receive it
+- Emitters use components to generate final HTML
+- Check [quartz/plugins/](mdc:quartz/plugins/) for relevant plugin APIs
\ No newline at end of file
diff --git a/.cursor/rules/content-authoring.mdc b/.cursor/rules/content-authoring.mdc
new file mode 100644
index 000000000..a7875011b
--- /dev/null
+++ b/.cursor/rules/content-authoring.mdc
@@ -0,0 +1,79 @@
+---
+globs: *.md
+description: Guidelines for authoring blog posts, research articles, and other markdown content
+---
+
+# Content Authoring Guidelines
+
+## Frontmatter Requirements
+All markdown files must include frontmatter with at minimum:
+```yaml
+---
+title: "Your Title Here"
+---
+```
+
+### Optional Frontmatter Fields
+- `description: "Brief description for SEO and previews"`
+- `tags: ["tag1", "tag2", "tag3"]` - For categorization
+- `draft: true` - To exclude from build (removed by RemoveDrafts plugin)
+- `aliases: ["alternative-url"]` - For URL redirects
+
+## Content Structure Best Practices
+
+### File Organization
+- **Blog posts**: Place in `content/blog/` with descriptive filenames
+- **Research**: Use `content/research/` for academic/technical papers
+- **Release notes**: Follow pattern in `content/releases/` with date-based naming
+- **Quick notes**: Use `content/notes/` for shorter thoughts and observations
+
+### Asset References
+- Store images and media in `content/assets/`
+- Reference assets relatively: ``
+- Use descriptive filenames for assets (avoid spaces, use hyphens)
+- Optimize images for web (prefer .webp for photos, .png for diagrams)
+
+### Writing Style
+- Use clear, descriptive headings (## and ###)
+- Include code blocks with proper language specification:
+ ```typescript
+ // Your code here
+ ```
+- For mathematical content, use LaTeX syntax with $ for inline math and $$ for blocks
+- Link to other content using wikilink syntax: `[[Other Page Title]]`
+
+### Content Types
+
+#### Blog Posts
+- Should tell a complete story or explain a concept thoroughly
+- Include relevant diagrams or code examples
+- Consider adding a brief description for better discoverability
+
+#### Research Articles
+- Follow academic formatting conventions
+- Include methodology, results, and conclusions sections
+- Reference external papers and sources appropriately
+
+#### Release Notes
+- Follow existing date-based naming convention (e.g., "Release Notes MM.DD.YY.md")
+- Include version numbers and brief feature summaries
+- Categorize changes (New Features, Bug Fixes, Improvements)
+
+#### Notes
+- Can be brief thoughts, observations, or work-in-progress ideas
+- Don't need to be complete articles
+- Good for capturing insights that might become full posts later
+
+## Markdown Extensions
+The site supports:
+- GitHub Flavored Markdown (tables, task lists, strikethrough)
+- Obsidian-style wikilinks `[[Page Name]]`
+- Math via KaTeX (`$inline$` and `$$block$$`)
+- Syntax highlighting for code blocks
+- Callouts (follow Obsidian syntax)
+
+## SEO Considerations
+- Use descriptive, unique titles
+- Include meta descriptions when appropriate
+- Use proper heading hierarchy (h1 → h2 → h3)
+- Internal linking helps with site navigation and SEO
\ No newline at end of file
diff --git a/.cursor/rules/project-structure.mdc b/.cursor/rules/project-structure.mdc
new file mode 100644
index 000000000..c78969727
--- /dev/null
+++ b/.cursor/rules/project-structure.mdc
@@ -0,0 +1,50 @@
+---
+alwaysApply: true
+---
+
+# Plastic Labs Blog - Project Structure Guide
+
+This is a Quartz-based blog for Plastic Labs. Understanding the project structure is essential for effective development.
+
+## Core Configuration
+- Main entry point: [quartz.config.ts](mdc:quartz.config.ts) - Quartz configuration including plugins, theme, and site settings
+- Layout configuration: [quartz.layout.ts](mdc:quartz.layout.ts) - Defines the visual layout and component arrangement
+- TypeScript config: [tsconfig.json](mdc:tsconfig.json) - TypeScript compilation settings
+- Package dependencies: [package.json](mdc:package.json) - Node.js dependencies and build scripts
+
+## Content Organization
+- **Main content directory**: [content/](mdc:content/) - All markdown content lives here
+ - `content/blog/` - Blog posts and articles
+ - `content/research/` - Research papers and findings
+ - `content/releases/` - Release notes and announcements
+ - `content/notes/` - Quick notes and thoughts
+ - `content/careers/` - Job postings and career-related content
+ - `content/extrusions/` - Special content type (monthly updates)
+ - `content/assets/` - Images, diagrams, and media assets
+ - `content/templates/` - Content templates (ignored in build)
+
+## Quartz Framework Structure
+- **Core framework**: [quartz/](mdc:quartz/) - Contains all Quartz framework code
+ - `quartz/components/` - React/Preact UI components (.tsx files)
+ - `quartz/plugins/` - Quartz plugins for content processing
+ - `quartz/styles/` - Global SCSS stylesheets
+ - `quartz/util/` - Utility functions and helpers
+ - `quartz/build.ts` - Main build system entry point
+
+## Build System
+- Built content outputs to `public/` directory
+- Static assets in `static/` are copied to root of public output via custom CopyStatic plugin
+- Uses esbuild for bundling and TypeScript compilation
+- Supports hot reloading during development
+
+## Key Conventions
+- All content files use markdown (.md) with frontmatter
+- Assets should be placed in `content/assets/` and referenced relatively
+- Custom components go in `quartz/components/`
+- Global styles in `quartz/styles/`, component-specific styles as .scss files in component directories
+
+## Theme Customization
+The site uses a custom dark/light theme with:
+- Monospace fonts (Departure Mono for headers, Roboto Mono for body)
+- Custom color scheme defined in quartz.config.ts
+- SCSS variables in [quartz/styles/variables.scss](mdc:quartz/styles/variables.scss)
\ No newline at end of file
diff --git a/.cursor/rules/quartz-configuration.mdc b/.cursor/rules/quartz-configuration.mdc
new file mode 100644
index 000000000..c552c6e28
--- /dev/null
+++ b/.cursor/rules/quartz-configuration.mdc
@@ -0,0 +1,185 @@
+---
+globs: quartz.config.ts,quartz.layout.ts
+description: Guidelines for configuring Quartz framework settings and layouts
+---
+
+# Quartz Configuration Guidelines
+
+## Core Configuration Files
+
+### quartz.config.ts
+Main configuration file containing:
+- Site metadata (title, baseUrl, analytics)
+- Theme settings (fonts, colors)
+- Plugin pipeline (transformers, filters, emitters)
+- Build settings and ignore patterns
+
+### quartz.layout.ts
+Defines visual layout and component arrangement for different page types.
+
+## Configuration Structure
+
+### Site Settings
+```typescript
+configuration: {
+ pageTitle: "🥽 Plastic Labs", // Site title in header
+ enableSPA: true, // Single-page app routing
+ enablePopovers: true, // Link preview popups
+ analytics: { provider: "postHog" }, // Analytics integration
+ baseUrl: "plasticlabs.ai", // Production domain
+ ignorePatterns: ["private", "templates"], // Exclude from build
+ locale: "en-US", // Language/locale
+ defaultDateType: "created", // Date display preference
+}
+```
+
+### Theme Configuration
+```typescript
+theme: {
+ cdnCaching: true, // Enable CDN for fonts
+ typography: {
+ header: "Departure Mono", // Header font
+ body: "Roboto Mono", // Body text font
+ code: "Ubuntu Mono", // Code block font
+ },
+ colors: {
+ lightMode: { /* color definitions */ },
+ darkMode: { /* color definitions */ }
+ }
+}
+```
+
+## Plugin Pipeline
+
+### Plugin Types
+1. **Transformers** - Process content during build
+2. **Filters** - Include/exclude content
+3. **Emitters** - Generate output files
+
+### Common Transformers
+```typescript
+transformers: [
+ Plugin.FrontMatter(), // Parse YAML frontmatter
+ Plugin.CreatedModifiedDate({ // Add file timestamps
+ priority: ["frontmatter", "filesystem"]
+ }),
+ Plugin.Latex({ renderEngine: "katex" }), // Math rendering
+ Plugin.SyntaxHighlighting({ // Code syntax highlighting
+ theme: { light: "github-light", dark: "github-dark" },
+ keepBackground: false
+ }),
+ Plugin.ObsidianFlavoredMarkdown(), // Wikilinks, callouts
+ Plugin.GitHubFlavoredMarkdown(), // Tables, task lists
+ Plugin.TableOfContents(), // Auto-generate TOCs
+ Plugin.CrawlLinks(), // Process internal links
+ Plugin.Description(), // Generate descriptions
+]
+```
+
+### Essential Emitters
+```typescript
+emitters: [
+ Plugin.AliasRedirects(), // Handle URL redirects
+ Plugin.ComponentResources({
+ fontOrigin: "googleFonts"
+ }), // Load external resources
+ Plugin.ContentPage(), // Generate content pages
+ Plugin.FolderPage(), // Generate folder indexes
+ Plugin.TagPage(), // Generate tag pages
+ Plugin.ContentIndex({ // Generate search index
+ enableSiteMap: true,
+ enableRSS: true
+ }),
+ Plugin.Assets(), // Copy content assets
+ CopyStatic(), // Custom: copy static/ files
+ Plugin.Static(), // Copy other static assets
+ Plugin.NotFoundPage(), // Generate 404 page
+]
+```
+
+## Layout Configuration
+
+### Page Layout Structure
+```typescript
+export const defaultContentPageLayout: PageLayout = {
+ beforeBody: [ // Above main content
+ Component.Breadcrumbs(),
+ Component.ArticleTitle(),
+ Component.ContentMeta(),
+ Component.TagList(),
+ ],
+ left: [ // Left sidebar
+ Component.PageTitle(),
+ Component.MobileOnly(Component.Spacer()),
+ Component.Search(),
+ Component.Darkmode(),
+ Component.DesktopOnly(Component.Explorer()),
+ ],
+ right: [ // Right sidebar
+ Component.Graph(),
+ Component.DesktopOnly(Component.TableOfContents()),
+ Component.Backlinks(),
+ ],
+}
+```
+
+### Responsive Components
+- `Component.MobileOnly()` - Hidden on desktop
+- `Component.DesktopOnly()` - Hidden on mobile
+- `Component.Spacer()` - Adds vertical spacing
+
+## Custom Plugins
+
+### Creating Custom Plugins
+Follow the pattern of the existing `CopyStatic` plugin:
+```typescript
+const CustomPlugin = () => ({
+ name: "CustomPlugin",
+ getQuartzComponents() {
+ return [] // Return components if needed
+ },
+ async emit({ argv, cfg }: BuildCtx): Promise {
+ // Plugin logic here
+ return outputFiles // Return generated file paths
+ }
+})
+```
+
+### Plugin Registration
+Add custom plugins to the appropriate pipeline section in `quartz.config.ts`.
+
+## Best Practices
+
+### Configuration Changes
+- Test configuration changes locally before deploying
+- Use TypeScript for type safety in config files
+- Keep plugin order consistent (some plugins depend on others)
+
+### Performance Optimization
+- Enable CDN caching for fonts when possible
+- Minimize the number of transformers for faster builds
+- Use `ignorePatterns` to exclude unnecessary files
+
+### Content Processing
+- Place transformers in logical order (FrontMatter should be first)
+- Configure syntax highlighting themes to match site theme
+- Enable SPA routing for better user experience
+
+### Development Workflow
+- Use `npx quartz build --serve` for local development
+- Check build output in `public/` directory
+- Verify that all required files are being generated
+
+## Troubleshooting
+
+### Common Issues
+- Plugin order matters - move problematic plugins earlier/later
+- Missing components in layout cause build failures
+- Invalid frontmatter breaks content processing
+- Asset path issues often relate to baseUrl configuration
+
+### Debug Tips
+- Check build logs for plugin errors
+- Validate frontmatter syntax in problematic files
+- Test individual plugins by temporarily removing others
+- Use `--verbose` flag for detailed build information
\ No newline at end of file
diff --git a/.cursor/rules/styling-conventions.mdc b/.cursor/rules/styling-conventions.mdc
new file mode 100644
index 000000000..94e85b1c4
--- /dev/null
+++ b/.cursor/rules/styling-conventions.mdc
@@ -0,0 +1,219 @@
+---
+globs: *.scss,*.css
+description: SCSS styling conventions and theme guidelines for the Plastic Labs blog
+---
+
+# SCSS Styling Conventions
+
+## File Organization
+
+### Global Styles
+- **Base styles**: [quartz/styles/base.scss](mdc:quartz/styles/base.scss) - Core HTML element styles
+- **Variables**: [quartz/styles/variables.scss](mdc:quartz/styles/variables.scss) - CSS custom properties and SCSS variables
+- **Custom styles**: [quartz/styles/custom.scss](mdc:quartz/styles/custom.scss) - Site-specific overrides
+
+### Component Styles
+- Component SCSS files live alongside their .tsx files in [quartz/components/styles/](mdc:quartz/components/styles/)
+- Name SCSS files to match component names (e.g., `search.scss` for Search component)
+- Import component styles in the component's .css property
+
+## Theme System
+
+### Color Variables
+Use CSS custom properties defined in the theme configuration:
+```scss
+.my-element {
+ background-color: var(--light);
+ color: var(--dark);
+ border: 1px solid var(--lightgray);
+}
+```
+
+### Available Color Variables
+- `--light` - Background color
+- `--lightgray` - Subtle elements (code, graph edges, outlines)
+- `--gray` - Graph nodes, medium contrast text
+- `--darkgray` - High contrast text
+- `--dark` - Primary text color
+- `--secondary` - Secondary text/UI elements
+- `--tertiary` - Accent color (green: #C0FFE1)
+- `--highlight` - Selection/hover backgrounds
+- `--customCallout` - Custom callout backgrounds
+
+### Typography Variables
+```scss
+.text-element {
+ font-family: var(--headerFont); // Departure Mono
+ font-family: var(--bodyFont); // Roboto Mono
+ font-family: var(--codeFont); // Ubuntu Mono
+}
+```
+
+## Responsive Design
+
+### Breakpoints
+Use consistent breakpoints across the site:
+```scss
+// Mobile-first approach
+.component {
+ // Mobile styles by default
+
+ @media (min-width: 600px) {
+ // Tablet styles
+ }
+
+ @media (min-width: 1200px) {
+ // Desktop styles
+ }
+}
+```
+
+### Display Classes
+Leverage existing responsive classes:
+- `.mobile-only` - Hidden on desktop
+- `.desktop-only` - Hidden on mobile/tablet
+
+## SCSS Best Practices
+
+### BEM Methodology
+Use Block-Element-Modifier naming:
+```scss
+.search-component { // Block
+ &__input { // Element
+ border: 1px solid var(--lightgray);
+
+ &--focused { // Modifier
+ border-color: var(--tertiary);
+ }
+ }
+
+ &__results { // Element
+ background: var(--light);
+ }
+}
+```
+
+### Nesting Guidelines
+- Limit nesting to 3 levels maximum
+- Use parent selectors (&) judiciously
+- Prefer flat selectors for better performance
+
+### Variable Usage
+```scss
+// Local variables for component-specific values
+.graph-component {
+ $node-size: 8px;
+ $link-opacity: 0.6;
+
+ .node {
+ width: $node-size;
+ height: $node-size;
+ }
+}
+```
+
+## Dark/Light Mode Support
+
+### Automatic Theme Switching
+Colors automatically switch based on the theme configuration. Always use CSS custom properties:
+
+```scss
+// ✅ Good - Uses theme variables
+.card {
+ background: var(--light);
+ border: 1px solid var(--lightgray);
+ color: var(--dark);
+}
+
+// ❌ Bad - Hard-coded colors
+.card {
+ background: #E2E2E2;
+ border: 1px solid #4e4e4e;
+ color: #4E4E4E;
+}
+```
+
+### Theme-Specific Overrides
+When necessary, use the body class for theme-specific styles:
+```scss
+.special-element {
+ // Default styles
+
+ :root[data-theme="dark"] & {
+ // Dark mode overrides
+ }
+}
+```
+
+## Animation Guidelines
+
+### Subtle Animations
+Keep animations minimal and performant:
+```scss
+.interactive-element {
+ transition: all 0.2s ease;
+
+ &:hover {
+ transform: translateY(-1px);
+ }
+}
+```
+
+### Reduced Motion
+Respect user preferences:
+```scss
+@media (prefers-reduced-motion: reduce) {
+ * {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ }
+}
+```
+
+## Common Patterns
+
+### Card Components
+```scss
+.card {
+ background: var(--light);
+ border: 1px solid var(--lightgray);
+ border-radius: 8px;
+ padding: 1rem;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+```
+
+### Interactive Elements
+```scss
+.button {
+ background: var(--tertiary);
+ color: var(--dark);
+ border: none;
+ padding: 0.5rem 1rem;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: opacity 0.2s ease;
+
+ &:hover {
+ opacity: 0.8;
+ }
+
+ &:focus {
+ outline: 2px solid var(--tertiary);
+ outline-offset: 2px;
+ }
+}
+```
+
+## Performance Considerations
+
+### Efficient Selectors
+- Avoid universal selectors (*) where possible
+- Use class selectors over element selectors for components
+- Minimize expensive properties (box-shadow, filters, transforms)
+
+### Asset Optimization
+- Use relative units (rem, em) for scalability
+- Prefer CSS transforms over changing layout properties
+- Test performance impact of new styles on slower devices
\ No newline at end of file
diff --git a/content/careers/Founding ML Engineer.md b/content/careers/Founding ML Engineer.md
deleted file mode 100644
index e648b6bd7..000000000
--- a/content/careers/Founding ML Engineer.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-title: Founding ML Engineer
-date: 02.24.25
-tags:
- - positions
- - product
- - dev
- - announcements
----
-
-(NYC, Full-Time)
-
-## About the Role
-
-We're seeking a leading machine learning engineer who can architect breakthrough systems while staying immersed in cutting-edge research. In direct collaboration with the CEO, you'll shape the future of AI at Plastic--tackling challenges across the entire machine learning stack.
-
-This role demands someone who thrives at the intersection of research and engineering; someone who can read and reproduce state-of-the-art papers, design novel architectures, and transform promising experiments into production-ready systems. You'll move fluidly between theoretical frameworks and practical implementation, making intuitive decisions about model architecture, quantization strategies, and serving infrastructure.
-
-We need a technical polymath who excels across the ML stack: from designing systematic experiments and running rigorous evaluations to building robust data pipelines and scalable model serving/inference systems. You should be particularly adept with post-training techniques that are redefining the field--from advanced inference-time computation methods to reinforcement learning with reasoning models.
-
-The LLM space moves at lightning speed, and so do we. You'll prototype rapidly while maintaining research rigor, implement robust MLOps practices, and craft observable systems that scale. Our small, interdisciplinary team moves fast--high agency is core to who we are. You'll have the freedom to directly impact our research and products to push the boundaries of what's possible in AI.
-
-We're building systems that haven't been built before, solving problems that haven't been solved. If you're a technical leader who thrives on these challenges and can serve as our ML north star, we want you on our team.
-
-## About You
-
-- 3+ years of applied ML experience with deep LLM expertise
-- High cultural alignment with Plastic Labs' ethos
-- NYC-based or open to NYC relocation
-- Strong command of a popular Python ML library (e.g PyTorch, TF, JAX, HF transformers, etc)
-- Experience replicating research papers soon after publication
-- Experience building and scaling robust inference systems
-- Practical experience with post-training and inference-time techniques (RL a plus)
-- Ability to build reliable MLOps pipelines that perform under load
-- Proficiency with Unix environments and developer tools (Git, Docker, etc.)
-- Up-to-date with the Open Source AI community and emerging technologies
-- Self-directed with a bias toward rapid execution
-- Driven to push language models beyond conventional boundaries
-- Background in cognitive sciences (CS, linguistics, neuroscience, philosophy, psychology, etc...) or related fields a plus
-
-> [!custom] [APPLY HERE](https://wellfound.com/l/2B3wwZ)
-
-## Research We're Excited About
-
-[s1: Simple test-time scaling](https://arxiv.org/abs/2501.19393)
-[Neural Networks Are Elastic Origami!](https://youtu.be/l3O2J3LMxqI?si=bhodv2c7GG75N2Ku)
-[Titans: Learning to Memorize at Test Time](https://arxiv.org/abs/2501.00663v1)
-[Mind Your Theory: Theory of Mind Goes Deeper Than Reasoning](https://arxiv.org/abs/2412.13631)
-[Generative Agent Simulations of 1,000 People](https://arxiv.org/abs/2411.10109)
-[DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning](https://arxiv.org/abs/2501.12948)
-[Multiagent Finetuning: Self Improvement with Diverse Reasoning Chains](https://arxiv.org/abs/2501.05707)
-[Prompt Programming for Large Language Models: Beyond the Few-Shot Paradigm](https://arxiv.org/pdf/2102.07350)
-[Theory of Mind May Have Spontaneously Emerged in Large Language Models](https://arxiv.org/pdf/2302.02083v3)
-[Think Twice: Perspective-Taking Improved Large Language Models' Theory-of-Mind Capabilities](https://arxiv.org/pdf/2311.10227)
-[Refusal in Language Models is Mediated by a Single Direction](https://arxiv.org/abs/2406.11717)
-[Representation Engineering: A Top-Down Approach to AI Transparency](https://arxiv.org/abs/2310.01405)
-[Theia Vogel's post on Representation Engineering Mistral 7B an Acid Trip](https://vgel.me/posts/representation-engineering/)
-[Cognitive Behaviors that Enable Self-Improving Reasoners](https://arxiv.org/abs/2503.01307)
-[All Roads Lead to Likelihood: The Value of Reinforcement Learning in Fine-Tuning](https://arxiv.org/abs/2503.01067)
-[A Roadmap to Pluralistic Alignment](https://arxiv.org/abs/2402.05070)
-[Open-Endedness is Essential for Artificial Superhuman Intelligence](https://arxiv.org/pdf/2406.04268)
-[Simulators](https://generative.ink/posts/simulators/)
-[Extended Mind Transformers](https://arxiv.org/pdf/2406.02332)
-[Violation of Expectation via Metacognitive Prompting Reduces Theory of Mind Prediction Error in Large Language Models](https://arxiv.org/abs/2310.06983)
-[Constitutional AI: Harmlessness from AI Feedback](https://arxiv.org/pdf/2212.08073)
-[Claude's Character](https://www.anthropic.com/research/claude-character)
-[Language Models Represent Space and Time](https://arxiv.org/pdf/2310.02207)
-[Generative Agents: Interactive Simulacra of Human Behavior](https://arxiv.org/abs/2304.03442)
-[Meta-Rewarding Language Models: Self-Improving Alignment with LLM-as-a-Meta-Judge](https://arxiv.org/abs/2407.19594)
-[Synthetic Sentience: Joscha Bach](https://www.youtube.com/watch?v=cs9Ls0m5QVE)
-[Cyborgism](https://www.lesswrong.com/posts/bxt7uCiHam4QXrQAA/cyborgism)
-[Spontaneous Reward Hacking in Iterative Self-Refinement](https://arxiv.org/abs/2407.04549)
-[... accompanying twitter thread](https://x.com/JanePan_/status/1813208688343052639)
-
-(Back to [[Working at Plastic]])
diff --git a/quartz.config.ts b/quartz.config.ts
index 08dde4abf..e3ef2e276 100644
--- a/quartz.config.ts
+++ b/quartz.config.ts
@@ -1,61 +1,67 @@
-import { QuartzConfig } from "./quartz/cfg"
-import * as Plugin from "./quartz/plugins"
-import { Argv, BuildCtx } from "./quartz/util/ctx"
-import fs from "fs"
-import path from "path"
-import { FilePath } from "./quartz/util/path"
-import { glob } from "./quartz/util/glob"
+import { QuartzConfig } from "./quartz/cfg";
+import * as Plugin from "./quartz/plugins";
+import { Argv, BuildCtx } from "./quartz/util/ctx";
+import fs from "fs";
+import path from "path";
+import { FilePath } from "./quartz/util/path";
+import { glob } from "./quartz/util/glob";
// Custom plugin to copy all files from static/ to the root of public/
const CopyStatic = () => ({
- name: "CopyStatic",
- getQuartzComponents() {
- return []
- },
- async emit({ argv, cfg }: BuildCtx): Promise {
- const staticPath = "static"
- const publicPath = argv.output
- try {
- // Ensure static path exists
- if (!fs.existsSync(staticPath)) {
- console.log("Static directory does not exist, skipping copy.")
- return []
- }
-
- // Use glob to find all files in static directory, respecting ignore patterns
- const files = await glob("**/*", staticPath, cfg.configuration.ignorePatterns)
- const outputFiles: FilePath[] = []
+ name: "CopyStatic",
+ getQuartzComponents() {
+ return [];
+ },
+ async emit({ argv, cfg }: BuildCtx): Promise {
+ const staticPath = "static";
+ const publicPath = argv.output;
+ try {
+ // Ensure static path exists
+ if (!fs.existsSync(staticPath)) {
+ console.log("Static directory does not exist, skipping copy.");
+ return [];
+ }
- for (const file of files) {
- const sourceFilePath = path.join(staticPath, file) as FilePath
-
- // Skip if it's a directory (glob might return directories)
- if ((await fs.promises.lstat(sourceFilePath)).isDirectory()) {
- continue;
- }
+ // Use glob to find all files in static directory, respecting ignore patterns
+ const files = await glob(
+ "**/*",
+ staticPath,
+ cfg.configuration.ignorePatterns,
+ );
+ const outputFiles: FilePath[] = [];
- const destFilePath = path.join(publicPath, file) as FilePath
- const destDir = path.dirname(destFilePath)
-
- // Ensure destination directory exists
- await fs.promises.mkdir(destDir, { recursive: true })
-
- // Copy file
- await fs.promises.copyFile(sourceFilePath, destFilePath)
- outputFiles.push(destFilePath)
- }
-
- if (outputFiles.length > 0) {
- console.log(`Successfully copied ${outputFiles.length} files from static/ to public/`)
- }
+ for (const file of files) {
+ const sourceFilePath = path.join(staticPath, file) as FilePath;
- return outputFiles
- } catch (err) {
- console.error("Error copying static files:", err)
- return []
- }
- }
-})
+ // Skip if it's a directory (glob might return directories)
+ if ((await fs.promises.lstat(sourceFilePath)).isDirectory()) {
+ continue;
+ }
+
+ const destFilePath = path.join(publicPath, file) as FilePath;
+ const destDir = path.dirname(destFilePath);
+
+ // Ensure destination directory exists
+ await fs.promises.mkdir(destDir, { recursive: true });
+
+ // Copy file
+ await fs.promises.copyFile(sourceFilePath, destFilePath);
+ outputFiles.push(destFilePath);
+ }
+
+ if (outputFiles.length > 0) {
+ console.log(
+ `Successfully copied ${outputFiles.length} files from static/ to public/`,
+ );
+ }
+
+ return outputFiles;
+ } catch (err) {
+ console.error("Error copying static files:", err);
+ return [];
+ }
+ },
+});
/**
* Quartz 4.0 Configuration
@@ -63,89 +69,92 @@ const CopyStatic = () => ({
* See https://quartz.jzhao.xyz/configuration for more information.
*/
const config: QuartzConfig = {
- configuration: {
- pageTitle: "🥽 Plastic Labs",
- enableSPA: true,
- enablePopovers: true,
- analytics: {
- provider: "postHog",
- },
- baseUrl: "plasticlabs.ai",
- ignorePatterns: ["private", "templates"],
- locale: "en-US",
- defaultDateType: "created",
- theme: {
- cdnCaching: true,
- typography: {
- header: "Departure Mono",
- body: "Roboto Mono",
- code: "Ubuntu Mono",
- },
- colors: {
- lightMode: {
- light: "#E2E2E2",
- lightgray: "#4e4e4e", //code, graph, outline
- gray: "#4e4e4e", // graph nodes
- darkgray: "#4e4e4e",
- dark: "#4E4E4E",
- secondary: "#4e4e4e",
- tertiary: "#C0FFE1",
- customCallout: "rgba(183, 255, 236, 0.35)",
- highlight: "rgba(128, 128, 128, 0.35)", //code bg, note bg, graph bg (ONLY ON LIGHT MODE)
- searchBackground: "#D3D3D3",
- },
- darkMode: {
- light: "#191919",
- lightgray: "#393639", //code, graph edges, outline
- gray: "#E2E2E2", //graph nodes
- darkgray: "#E2E2E2",
- dark: "#ebebec",
- secondary: "#7C7C7C",
- tertiary: "#C0FFE1",
- highlight: "rgba(125, 125, 125, 0.15)", //code bg, note bg
- customCallout: "#00b8d410",
- searchBackground: "#252525",
- },
- },
- },
- },
- plugins: {
- transformers: [
- Plugin.FrontMatter(),
- Plugin.CreatedModifiedDate({
- priority: ["frontmatter", "filesystem"],
- }),
- Plugin.Latex({ renderEngine: "katex" }),
- Plugin.SyntaxHighlighting({
- theme: {
- light: "github-light",
- dark: "github-dark",
- },
- keepBackground: false,
- }),
- Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }),
- Plugin.GitHubFlavoredMarkdown({ enableSmartyPants: false }),
- Plugin.TableOfContents(),
- Plugin.CrawlLinks({ markdownLinkResolution: "shortest" }),
- Plugin.Description(),
- ],
- filters: [Plugin.RemoveDrafts()],
- emitters: [
- Plugin.AliasRedirects(),
- Plugin.ComponentResources({ fontOrigin: "googleFonts" }),
- Plugin.ContentPage(),
- Plugin.FolderPage(),
- Plugin.TagPage(),
- Plugin.ContentIndex({
- enableSiteMap: true,
- enableRSS: true,
- }),
- Plugin.Assets(),
- CopyStatic(),
- Plugin.Static(),
- Plugin.NotFoundPage(),
- ],
- },
-}
+ configuration: {
+ pageTitle: "🥽 Plastic Labs",
+ enableSPA: true,
+ enablePopovers: true,
+ analytics: {
+ provider: "postHog",
+ },
+ baseUrl: "blog.plasticlabs.ai",
+ ignorePatterns: ["private", "templates"],
+ locale: "en-US",
+ defaultDateType: "created",
+ theme: {
+ cdnCaching: true,
+ typography: {
+ header: "Departure Mono",
+ body: "Roboto Mono",
+ code: "Ubuntu Mono",
+ },
+ colors: {
+ lightMode: {
+ light: "#E2E2E2",
+ lightgray: "#4e4e4e", //code, graph, outline
+ gray: "#4e4e4e", // graph nodes
+ darkgray: "#4e4e4e",
+ dark: "#4E4E4E",
+ secondary: "#4e4e4e",
+ tertiary: "#C0FFE1",
+ customCallout: "rgba(183, 255, 236, 0.35)",
+ highlight: "rgba(128, 128, 128, 0.35)", //code bg, note bg, graph bg (ONLY ON LIGHT MODE)
+ searchBackground: "#D3D3D3",
+ },
+ darkMode: {
+ light: "#191919",
+ lightgray: "#393639", //code, graph edges, outline
+ gray: "#E2E2E2", //graph nodes
+ darkgray: "#E2E2E2",
+ dark: "#ebebec",
+ secondary: "#7C7C7C",
+ tertiary: "#C0FFE1",
+ highlight: "rgba(125, 125, 125, 0.15)", //code bg, note bg
+ customCallout: "#00b8d410",
+ searchBackground: "#252525",
+ },
+ },
+ },
+ },
+ plugins: {
+ transformers: [
+ Plugin.FrontMatter(),
+ Plugin.CreatedModifiedDate({
+ priority: ["frontmatter", "filesystem"],
+ }),
+ Plugin.Latex({ renderEngine: "katex" }),
+ Plugin.SyntaxHighlighting({
+ theme: {
+ light: "github-light",
+ dark: "github-dark",
+ },
+ keepBackground: false,
+ }),
+ Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }),
+ Plugin.GitHubFlavoredMarkdown({ enableSmartyPants: false }),
+ Plugin.TableOfContents(),
+ Plugin.CrawlLinks({ markdownLinkResolution: "shortest" }),
+ Plugin.Description(),
+ Plugin.OpenGraphImage({
+ defaultImage: "/og-image.png",
+ }),
+ ],
+ filters: [Plugin.RemoveDrafts()],
+ emitters: [
+ Plugin.AliasRedirects(),
+ Plugin.ComponentResources({ fontOrigin: "googleFonts" }),
+ Plugin.ContentPage(),
+ Plugin.FolderPage(),
+ Plugin.TagPage(),
+ Plugin.ContentIndex({
+ enableSiteMap: true,
+ enableRSS: true,
+ }),
+ Plugin.Assets(),
+ CopyStatic(),
+ Plugin.Static(),
+ Plugin.NotFoundPage(),
+ ],
+ },
+};
-export default config
+export default config;
diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx
index 3cb6bea66..0d4a5d23a 100644
--- a/quartz/components/Head.tsx
+++ b/quartz/components/Head.tsx
@@ -15,7 +15,20 @@ export default (() => {
const baseDir = fileData.slug === "404" ? path : pathToRoot(fileData.slug!)
const iconPath = joinSegments(baseDir, "static/icon.png")
- const ogImagePath = `https://${cfg.baseUrl}/static/og-image.png`
+
+ // Use dynamic opengraph image from plugin, fallback to default
+ const ogImagePath = fileData.opengraphImage
+ ? (fileData.opengraphImage.startsWith('http')
+ ? fileData.opengraphImage
+ : `https://${cfg.baseUrl}${fileData.opengraphImage}`)
+ : `https://${cfg.baseUrl}/og-image.png`
+
+ // Twitter image (same as OpenGraph)
+ const twitterImagePath = fileData.twitterImage
+ ? (fileData.twitterImage.startsWith('http')
+ ? fileData.twitterImage
+ : `https://${cfg.baseUrl}${fileData.twitterImage}`)
+ : ogImagePath
return (
@@ -33,6 +46,10 @@ export default (() => {
{cfg.baseUrl && }
+
+
+
+ {cfg.baseUrl && }
diff --git a/quartz/plugins/transformers/index.ts b/quartz/plugins/transformers/index.ts
index e340f10e7..18ccc207d 100644
--- a/quartz/plugins/transformers/index.ts
+++ b/quartz/plugins/transformers/index.ts
@@ -9,3 +9,4 @@ export { OxHugoFlavouredMarkdown } from "./oxhugofm"
export { SyntaxHighlighting } from "./syntax"
export { TableOfContents } from "./toc"
export { HardLineBreaks } from "./linebreaks"
+export { OpenGraphImage } from "./opengraphImage"
diff --git a/quartz/plugins/transformers/opengraphImage.ts b/quartz/plugins/transformers/opengraphImage.ts
new file mode 100644
index 000000000..dba33532c
--- /dev/null
+++ b/quartz/plugins/transformers/opengraphImage.ts
@@ -0,0 +1,99 @@
+import { Root as HTMLRoot } from "hast"
+import { visit } from "unist-util-visit"
+import { QuartzTransformerPlugin } from "../types"
+import { FilePath, joinSegments, pathToRoot, isRelativeURL } from "../../util/path"
+
+export interface Options {
+ defaultImage: string
+}
+
+const defaultOptions: Options = {
+ defaultImage: "/og-image.png",
+}
+
+function coalesceImageAliases(data: { [key: string]: any }, aliases: string[]): string | undefined {
+ for (const alias of aliases) {
+ if (data[alias] !== undefined && data[alias] !== null && typeof data[alias] === "string") {
+ return data[alias]
+ }
+ }
+ return undefined
+}
+
+export const OpenGraphImage: QuartzTransformerPlugin | undefined> = (userOpts) => {
+ const opts = { ...defaultOptions, ...userOpts }
+
+ return {
+ name: "OpenGraphImage",
+ htmlPlugins() {
+ return [
+ () => {
+ return async (tree: HTMLRoot, file) => {
+ let opengraphImage: string | undefined
+
+ // Priority 1: Check frontmatter for opengraph image
+ const frontmatterImage = coalesceImageAliases(
+ file.data.frontmatter || {},
+ ["opengraph_image", "og_image", "opengraphImage", "ogImage"]
+ )
+
+ if (frontmatterImage) {
+ opengraphImage = frontmatterImage
+ } else {
+ // Priority 2: Find first image in content
+ let firstImage: string | undefined
+
+ visit(tree, "element", (node) => {
+ if (firstImage) return // Already found one
+
+ if (node.tagName === "img" && node.properties?.src) {
+ const src = node.properties.src.toString()
+ firstImage = src
+ }
+ })
+
+ if (firstImage) {
+ opengraphImage = firstImage
+ } else {
+ // Priority 3: Use default image
+ opengraphImage = opts.defaultImage
+ }
+ }
+
+ // Convert relative URLs to absolute paths from site root
+ if (opengraphImage && isRelativeURL(opengraphImage)) {
+ // If the image starts with "/" it's already relative to root, keep as-is
+ if (opengraphImage.startsWith("/")) {
+ // Already absolute path from root
+ opengraphImage = opengraphImage
+ } else {
+ // Relative path like "../assets/image.png" - convert to absolute
+ // Images in content are typically in the assets directory
+ if (opengraphImage.includes("../assets/")) {
+ opengraphImage = opengraphImage.replace(/\.\.\/+assets\//, "/assets/")
+ } else if (opengraphImage.includes("assets/")) {
+ opengraphImage = "/" + opengraphImage.replace(/^\.\/+/, "")
+ } else {
+ // Other relative paths - assume they're relative to content root
+ opengraphImage = "/" + opengraphImage.replace(/^\.\.\/+/, "")
+ }
+ }
+ }
+
+ // Store the opengraph image in file data for use by Head component
+ file.data.opengraphImage = opengraphImage
+ // Also set for Twitter cards (same image)
+ file.data.twitterImage = opengraphImage
+ }
+ },
+ ]
+ },
+ }
+}
+
+declare module "vfile" {
+ interface DataMap {
+ opengraphImage: string
+ twitterImage: string
+ }
+}
diff --git a/static/og-image.png b/static/og-image.png
new file mode 100644
index 0000000000000000000000000000000000000000..e8864e5c1020243aee79d542c8f55746cbfc6db5
GIT binary patch
literal 30658
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
literal 0
HcmV?d00001