Initial commit

This commit is contained in:
Jennie Robinson Faber 2025-11-11 19:12:21 +00:00
commit 92e96b9107
85 changed files with 24969 additions and 0 deletions

46
.env.example Normal file
View file

@ -0,0 +1,46 @@
# MongoDB Connection
MONGODB_URI=mongodb://localhost:27017/wiki-ghostguild
# Authentication
JWT_SECRET=your-secret-key-change-in-production
JWT_REFRESH_SECRET=your-refresh-secret-change-in-production
# Ghost Guild OAuth Integration
GHOSTGUILD_API_URL=https://ghostguild.org/api
GHOSTGUILD_API_KEY=your-api-key
GHOSTGUILD_CLIENT_ID=your-client-id
GHOSTGUILD_CLIENT_SECRET=your-client-secret
GHOSTGUILD_REDIRECT_URI=https://wiki.ghostguild.org/api/auth/callback
# Site Configuration
SITE_URL=https://wiki.ghostguild.org
SITE_NAME=Ghost Guild Knowledge Commons
SITE_DESCRIPTION=Collaborative knowledge base for the Baby Ghosts community
# Forgejo Integration
FORGEJO_URL=https://git.ghostguild.org
FORGEJO_TOKEN=your-forgejo-token
FORGEJO_REPO=ghostguild/wiki-content
# Search (Meilisearch)
MEILISEARCH_URL=http://localhost:7700
MEILISEARCH_KEY=your-master-key
# Email (for notifications)
EMAIL_FROM=wiki@ghostguild.org
EMAIL_SMTP_HOST=smtp.example.com
EMAIL_SMTP_PORT=587
EMAIL_SMTP_USER=your-smtp-user
EMAIL_SMTP_PASS=your-smtp-password
# Analytics (Optional)
PLAUSIBLE_DOMAIN=wiki.ghostguild.org
PLAUSIBLE_API_KEY=your-plausible-key
# Error Tracking (Optional)
SENTRY_DSN=your-sentry-dsn
SENTRY_ENVIRONMENT=production
# Development
NODE_ENV=development
DEBUG=false

38
.gitignore vendored Normal file
View file

@ -0,0 +1,38 @@
# Nuxt dev/build outputs
.output
.data
.nuxt
.nitro
.cache
dist
# Node dependencies
node_modules
# Logs
logs
*.log
# Misc
.DS_Store
.fleet
.idea
# Obsidian vault (user-specific workspace settings)
.obsidian/workspace.json
.obsidian/workspace-mobile.json
.obsidian/graph.json
.obsidian/appearance.json
.obsidian/cache/
.obsidian/plugins/*/data.json
conflict-files-obsidian-git.md
.trash/
# Local env files
.env
.env.*
!.env.example
/*.md
/migration/*
MIGRATION_STATUS.txt

2
.npmrc Normal file
View file

@ -0,0 +1,2 @@
ignore-scripts=true
optional=false

31
Dockerfile Normal file
View file

@ -0,0 +1,31 @@
# Build stage
FROM node:20-slim AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm install --yes --omit=dev
# Copy source
COPY . .
# Generate static site
RUN npm run generate
# Production stage - static nginx server
FROM nginx:alpine
# Copy nginx config
COPY nginx.conf /etc/nginx/nginx.conf
# Copy generated static files from builder
COPY --from=builder /app/.output/public /usr/share/nginx/html
# Expose port
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]

14
app/app.vue Normal file
View file

@ -0,0 +1,14 @@
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
<script setup>
// Initialize auth on app mount
const { fetchUser } = useAuth()
onMounted(async () => {
await fetchUser()
})
</script>

56
app/assets/css/main.css Normal file
View file

@ -0,0 +1,56 @@
@import "tailwindcss";
@layer components {
/* Custom prose styles */
.prose {
@apply max-w-none;
}
/* Article content styles */
.article-content {
@apply max-w-none leading-relaxed;
}
.article-content h1 {
@apply text-3xl font-bold mb-4 mt-6;
}
.article-content h2 {
@apply text-2xl font-semibold mb-3 mt-8;
}
.article-content h3 {
@apply text-xl font-semibold mb-2 mt-6;
}
.article-content p {
@apply mb-4;
}
.article-content ul,
.article-content ol {
@apply mb-4 ml-6;
}
.article-content li {
@apply mb-2;
}
.article-content code {
@apply bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-sm font-mono;
}
.article-content pre {
@apply bg-gray-100 dark:bg-gray-800 p-4 rounded-lg overflow-x-auto mb-4;
}
/* Editor styles */
.editor-container {
@apply min-h-[500px] border rounded-lg;
}
/* Comment thread styles */
.comment-thread {
@apply border-l-2 border-gray-200 dark:border-gray-700 pl-4 ml-4;
}
}

View file

@ -0,0 +1,70 @@
import type { User } from "../types/auth";
export const useAuth = () => {
const user = useState<User | null>("auth.user", () => null);
const isAuthenticated = computed(() => !!user.value);
const login = () => {
// Redirect to login endpoint
navigateTo("/api/auth/login", { external: true });
};
const logout = async () => {
try {
await $fetch("/api/auth/logout", { method: "POST" });
user.value = null;
await navigateTo("/");
} catch (error) {
console.error("Logout failed:", error);
}
};
const fetchUser = async () => {
try {
const userData = await $fetch<User>("/api/auth/me");
user.value = userData;
return userData;
} catch (error) {
user.value = null;
return null;
}
};
const hasRole = (role: string) => {
return user.value?.roles?.includes(role) || false;
};
const hasPermission = (
permission: "canEdit" | "canModerate" | "canAdmin",
) => {
return user.value?.permissions?.[permission] || false;
};
const canAccessContent = (accessLevel: string, cohorts?: string[]) => {
if (accessLevel === "public") return true;
if (!isAuthenticated.value) return false;
switch (accessLevel) {
case "member":
return true;
case "cohort":
if (!cohorts || cohorts.length === 0) return true;
return cohorts.some((c) => hasRole(`cohort-${c}`));
case "admin":
return hasPermission("canAdmin");
default:
return false;
}
};
return {
user: readonly(user),
isAuthenticated: readonly(isAuthenticated),
login,
logout,
fetchUser,
hasRole,
hasPermission,
canAccessContent,
};
};

45
app/layouts/default.vue Normal file
View file

@ -0,0 +1,45 @@
<template>
<div class="min-h-screen bg-gray-50 dark:bg-gray-900">
<!-- Navigation -->
<nav class="bg-white dark:bg-gray-800 shadow">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex items-center">
<NuxtLink to="/" class="text-xl font-bold text-gray-900 dark:text-white">
Wiki.GhostGuild
</NuxtLink>
<div class="ml-10 flex space-x-4">
<NuxtLink to="/articles" class="text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white px-3 py-2 rounded-md">
Articles
</NuxtLink>
<NuxtLink v-if="isAuthenticated" to="/articles/new" class="text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white px-3 py-2 rounded-md">
New Article
</NuxtLink>
</div>
</div>
<div class="flex items-center space-x-4">
<div v-if="isAuthenticated" class="flex items-center space-x-4">
<span class="text-gray-700 dark:text-gray-300">{{ user?.displayName }}</span>
<button @click="logout" class="text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white">
Logout
</button>
</div>
<button v-else @click="login" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700">
Login
</button>
</div>
</div>
</div>
</nav>
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<slot />
</main>
</div>
</template>
<script setup>
const { user, isAuthenticated, login, logout } = useAuth()
</script>

View file

@ -0,0 +1,163 @@
<template>
<div>
<!-- Loading State -->
<div v-if="pending" class="text-center py-8">
<div class="text-gray-600 dark:text-gray-400">Loading article...</div>
</div>
<!-- Error State -->
<div v-else-if="!article" class="text-center py-8">
<div class="text-red-600 dark:text-red-400">Article not found</div>
<NuxtLink
to="/articles"
class="text-blue-600 hover:text-blue-800 mt-4 inline-block"
>
Back to Articles
</NuxtLink>
</div>
<!-- Article Content -->
<article v-else class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-8">
<!-- Header -->
<div class="border-b border-gray-200 dark:border-gray-700 pb-6 mb-6">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white mb-4">
{{ article.title }}
</h1>
<div
class="flex flex-wrap gap-4 text-sm text-gray-600 dark:text-gray-400"
>
<span>By {{ article.author || "Unknown" }}</span>
<span v-if="article.publishedAt">
{{ new Date(article.publishedAt).toLocaleDateString() }}
</span>
<span
v-if="article.category"
class="px-2 py-1 bg-gray-100 dark:bg-gray-700 rounded"
>
{{ article.category }}
</span>
<span
v-if="article.accessLevel && article.accessLevel !== 'public'"
class="text-orange-600 dark:text-orange-400"
>
🔒 {{ article.accessLevel }}
</span>
</div>
<!-- Edit Button (for future use) -->
<!-- <div v-if="canEdit" class="mt-4">
<NuxtLink
:to="`${article._path}/edit`"
class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700"
>
Edit Article
</NuxtLink>
</div> -->
</div>
<!-- Access Control Warning -->
<div
v-if="article.accessLevel === 'member'"
class="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4 mb-6"
>
<p class="text-blue-800 dark:text-blue-200">
👥 This content is for Baby Ghosts members only
</p>
</div>
<div
v-else-if="article.accessLevel === 'cohort'"
class="bg-purple-50 dark:bg-purple-900/20 border border-purple-200 dark:border-purple-800 rounded-lg p-4 mb-6"
>
<p class="text-purple-800 dark:text-purple-200">
🔒 This content is for a specific cohort
</p>
</div>
<div
v-else-if="article.accessLevel === 'admin'"
class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 mb-6"
>
<p class="text-red-800 dark:text-red-200">
🔐 This is internal/admin content
</p>
</div>
<!-- Article Body -->
<div class="prose prose-lg dark:prose-invert max-w-none">
<ContentRenderer :value="article" />
</div>
<!-- Tags -->
<div
v-if="article.tags?.length"
class="mt-8 pt-6 border-t border-gray-200 dark:border-gray-700"
>
<div class="flex flex-wrap gap-2">
<span
v-for="tag in article.tags"
:key="tag"
class="px-3 py-1 bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-full text-sm"
>
#{{ tag }}
</span>
</div>
</div>
<!-- Navigation -->
<div
class="mt-8 pt-6 border-t border-gray-200 dark:border-gray-700 flex gap-4"
>
<NuxtLink
to="/articles"
class="text-blue-600 hover:text-blue-800 dark:text-blue-400"
>
Back to Articles
</NuxtLink>
</div>
</article>
</div>
</template>
<script setup>
const route = useRoute();
const slug = route.params.slug;
const getArticleSlug = (article) => {
if (!article) return "";
const candidate =
article.slug ||
article.stem ||
article._path ||
article._id ||
article.id ||
"";
const segments = candidate.split("/").filter(Boolean);
return segments[segments.length - 1] || "";
};
// Fetch article from Nuxt Content
const { data: article, pending } = await useAsyncData(
`article-${slug}`,
async () => {
const articles = await queryCollection("articles").all();
return articles.find((a) => getArticleSlug(a) === slug);
},
);
// SEO
useHead({
title: () => article.value?.title || "Article",
meta: [
{ name: "description", content: () => article.value?.description || "" },
],
});
// Watch for route changes
watch(
() => route.params.slug,
() => {
// Route change will trigger new useAsyncData
},
{ immediate: true },
);
</script>

View file

@ -0,0 +1,158 @@
<template>
<div>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white mb-6">
Articles
</h1>
<!-- Search and Filters -->
<div class="bg-white dark:bg-gray-800 p-4 rounded-lg shadow mb-6">
<div class="flex gap-4">
<input
v-model="search"
type="text"
placeholder="Search articles..."
class="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
/>
<select
v-model="selectedCategory"
class="px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
>
<option value="">All Categories</option>
<option value="operations">Operations</option>
<option value="funding">Funding</option>
<option value="strategy">Strategy</option>
<option value="templates">Templates</option>
<option value="programs">Programs</option>
</select>
</div>
</div>
<!-- Articles List -->
<div v-if="filteredArticles.length" class="space-y-4">
<article
v-for="article in filteredArticles"
:key="article._path || article.stem || getArticleSlug(article)"
class="bg-white dark:bg-gray-800 p-6 rounded-lg shadow hover:shadow-lg transition-shadow"
>
<div class="flex justify-between items-start">
<div class="flex-1">
<NuxtLink
:to="getArticlePath(article)"
class="text-xl font-semibold text-blue-600 hover:text-blue-800 dark:text-blue-400"
>
{{ article.title }}
</NuxtLink>
<p class="text-gray-600 dark:text-gray-400 mt-2">
{{ article.description }}
</p>
<div
class="mt-3 flex items-center gap-4 text-sm text-gray-500 dark:text-gray-400"
>
<span class="px-2 py-1 bg-gray-100 dark:bg-gray-700 rounded">
{{ article.category || "uncategorized" }}
</span>
<span>By {{ article.author || "Unknown" }}</span>
<span v-if="article.publishedAt">
{{ new Date(article.publishedAt).toLocaleDateString() }}
</span>
<span
v-if="article.accessLevel && article.accessLevel !== 'public'"
class="text-orange-600 dark:text-orange-400"
>
🔒 {{ article.accessLevel }}
</span>
</div>
</div>
</div>
</article>
</div>
<div v-else class="text-center py-8">
<p class="text-gray-600 dark:text-gray-400">
{{
search || selectedCategory
? "No articles found matching your filters"
: "No articles available"
}}
</p>
</div>
</div>
</template>
<script setup>
const search = ref("");
const selectedCategory = ref("");
// Fetch all articles from Nuxt Content
const { data: articles } = await useAsyncData("articles", () =>
queryCollection("articles").all(),
);
// Helper function to extract title from body
const getArticleTitle = (article) => {
// Try to get title from frontmatter first
if (
article.title &&
typeof article.title === "string" &&
article.title !== "[object Object]"
) {
return article.title;
}
// Fallback: extract from first H1 in body
if (article.meta?.body?.value && Array.isArray(article.meta.body.value)) {
const h1 = article.meta.body.value.find(
(node) => Array.isArray(node) && node[0] === "h1",
);
if (h1 && h1[2]) {
return h1[2];
}
}
return "Untitled";
};
// Resolve the correct Nuxt route for an article entry
const getArticleSlug = (article) => {
if (!article) return "";
const candidate =
article.slug ||
article.stem ||
article._path ||
article._id ||
article.id ||
"";
const segments = candidate.split("/").filter(Boolean);
return segments[segments.length - 1] || "";
};
const getArticlePath = (article) => {
const slug = getArticleSlug(article);
return slug ? `/articles/${slug}` : "/articles";
};
// Filter and search articles
const filteredArticles = computed(() => {
if (!articles.value) return [];
return articles.value.filter((article) => {
const title = getArticleTitle(article);
const matchesSearch =
!search.value ||
title?.toLowerCase().includes(search.value.toLowerCase()) ||
article.description?.toLowerCase().includes(search.value.toLowerCase());
const matchesCategory =
!selectedCategory.value || article.category === selectedCategory.value;
return matchesSearch && matchesCategory;
});
});
// Watch for search changes
watch(search, () => {
// Trigger reactivity
});
</script>

228
app/pages/articles/new.vue Normal file
View file

@ -0,0 +1,228 @@
<template>
<div class="max-w-4xl mx-auto">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white mb-6">Create New Article</h1>
<form @submit.prevent="createArticle" class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-8">
<!-- Title -->
<div class="mb-6">
<label for="title" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Title
</label>
<input
v-model="form.title"
id="title"
type="text"
required
class="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
placeholder="Article title"
>
</div>
<!-- Slug -->
<div class="mb-6">
<label for="slug" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
URL Slug
</label>
<input
v-model="form.slug"
id="slug"
type="text"
required
pattern="[a-z0-9-]+"
class="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
placeholder="article-url-slug"
>
<p class="text-sm text-gray-500 mt-1">Lowercase letters, numbers, and hyphens only</p>
</div>
<!-- Description -->
<div class="mb-6">
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Description
</label>
<textarea
v-model="form.description"
id="description"
rows="2"
class="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
placeholder="Brief description of the article"
></textarea>
</div>
<!-- Category -->
<div class="mb-6">
<label for="category" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Category
</label>
<select
v-model="form.category"
id="category"
class="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
>
<option value="operations">Operations</option>
<option value="funding">Funding</option>
<option value="strategy">Strategy</option>
<option value="templates">Templates</option>
<option value="programs">Programs</option>
</select>
</div>
<!-- Access Level -->
<div class="mb-6">
<label for="accessLevel" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Access Level
</label>
<select
v-model="form.accessLevel"
id="accessLevel"
class="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
>
<option value="public">Public</option>
<option value="member">Members Only</option>
<option value="cohort">Cohort Only</option>
<option value="admin" v-if="hasPermission('canAdmin')">Admin Only</option>
</select>
</div>
<!-- Content -->
<div class="mb-6">
<label for="content" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Content (Markdown)
</label>
<textarea
v-model="form.content"
id="content"
rows="20"
required
class="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white font-mono text-sm"
placeholder="Write your article in Markdown..."
></textarea>
</div>
<!-- Tags -->
<div class="mb-6">
<label for="tags" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Tags (comma-separated)
</label>
<input
v-model="tagsInput"
id="tags"
type="text"
class="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
placeholder="tag1, tag2, tag3"
>
</div>
<!-- Status -->
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Status
</label>
<div class="flex gap-4">
<label class="flex items-center">
<input
v-model="form.status"
type="radio"
value="draft"
class="mr-2"
>
<span class="text-gray-700 dark:text-gray-300">Save as Draft</span>
</label>
<label class="flex items-center">
<input
v-model="form.status"
type="radio"
value="published"
class="mr-2"
>
<span class="text-gray-700 dark:text-gray-300">Publish Now</span>
</label>
</div>
</div>
<!-- Error Message -->
<div v-if="error" class="mb-6 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
<p class="text-red-800 dark:text-red-200">{{ error }}</p>
</div>
<!-- Submit Buttons -->
<div class="flex gap-4">
<button
type="submit"
:disabled="loading"
class="bg-blue-600 text-white px-6 py-2 rounded-md hover:bg-blue-700 disabled:opacity-50"
>
{{ loading ? 'Creating...' : 'Create Article' }}
</button>
<NuxtLink to="/articles" class="bg-gray-300 dark:bg-gray-600 text-gray-700 dark:text-gray-300 px-6 py-2 rounded-md hover:bg-gray-400 dark:hover:bg-gray-500">
Cancel
</NuxtLink>
</div>
</form>
</div>
</template>
<script setup>
const { hasPermission, isAuthenticated } = useAuth()
const router = useRouter()
// Redirect if not authenticated
if (!isAuthenticated.value) {
navigateTo('/api/auth/login', { external: true })
}
const form = ref({
title: '',
slug: '',
description: '',
category: 'operations',
accessLevel: 'member',
content: '',
status: 'draft'
})
const tagsInput = ref('')
const loading = ref(false)
const error = ref('')
// Auto-generate slug from title
watch(() => form.value.title, (title) => {
if (!form.value.slug || form.value.slug === slugify(title.slice(0, -1))) {
form.value.slug = slugify(title)
}
})
function slugify(text) {
return text
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
}
async function createArticle() {
loading.value = true
error.value = ''
try {
const tags = tagsInput.value
.split(',')
.map(t => t.trim())
.filter(t => t)
const response = await $fetch('/api/articles', {
method: 'POST',
body: {
...form.value,
tags
}
})
// Redirect to the new article
await router.push(`/articles/${response.slug}`)
} catch (err) {
error.value = err.data?.message || 'Failed to create article'
} finally {
loading.value = false
}
}
</script>

108
app/pages/index.vue Normal file
View file

@ -0,0 +1,108 @@
<template>
<div>
<h1 class="text-4xl font-bold text-gray-900 dark:text-white mb-4">
Ghost Guild Knowledge Commons
</h1>
<p class="text-xl text-gray-600 dark:text-gray-400 mb-8">
Collaborative knowledge base for the Baby Ghosts community
</p>
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="bg-white dark:bg-gray-800 p-6 rounded-lg shadow">
<h2 class="text-xl font-semibold mb-2">📚 Browse Articles</h2>
<p class="text-gray-600 dark:text-gray-400 mb-4">
Explore our growing collection of guides and resources
</p>
<NuxtLink to="/articles" class="text-blue-600 hover:text-blue-800">
View All Articles
</NuxtLink>
</div>
<div
v-if="isAuthenticated"
class="bg-white dark:bg-gray-800 p-6 rounded-lg shadow"
>
<h2 class="text-xl font-semibold mb-2"> Contribute</h2>
<p class="text-gray-600 dark:text-gray-400 mb-4">
Share your knowledge with the community
</p>
<NuxtLink to="/articles/new" class="text-blue-600 hover:text-blue-800">
Create Article
</NuxtLink>
</div>
<div class="bg-white dark:bg-gray-800 p-6 rounded-lg shadow">
<h2 class="text-xl font-semibold mb-2">👥 Community</h2>
<p class="text-gray-600 dark:text-gray-400 mb-4">
Connect with other Baby Ghosts members
</p>
<a
href="https://ghostguild.org"
class="text-blue-600 hover:text-blue-800"
>
Visit Ghost Guild
</a>
</div>
</div>
<!-- Recent Articles -->
<div class="mt-12">
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-6">
Recent Articles
</h2>
<div v-if="pending" class="text-gray-600 dark:text-gray-400">
Loading...
</div>
<div v-else-if="articles?.length" class="space-y-4">
<article
v-for="article in articles"
:key="article.slug"
class="bg-white dark:bg-gray-800 p-4 rounded-lg shadow"
>
<NuxtLink
:to="`/articles/${article.slug}`"
class="text-xl font-semibold text-blue-600 hover:text-blue-800"
>
{{ article.title }}
</NuxtLink>
<p class="text-gray-600 dark:text-gray-400 mt-2">
{{ article.description }}
</p>
<div class="mt-2 text-sm text-gray-500">
<span>{{ article.category }}</span>
<span>{{
new Date(article.publishedAt).toLocaleDateString()
}}</span>
</div>
</article>
</div>
</div>
</div>
</template>
<script setup>
const { isAuthenticated } = useAuth();
// Fetch recent articles from Nuxt Content to keep generate static-friendly
const { data: recentArticles, pending } = await useAsyncData(
"recent-articles",
async () => {
const entries = await queryCollection("articles").all();
const getTimestamp = (value) => {
if (!value) {
return 0;
}
const date = new Date(value);
return Number.isNaN(date.getTime()) ? 0 : date.getTime();
};
return entries
.filter((article) => article.published !== false)
.sort((a, b) => getTimestamp(b.publishedAt) - getTimestamp(a.publishedAt))
.slice(0, 5);
},
);
const articles = computed(() => recentArticles.value || []);
</script>

View file

@ -0,0 +1,31 @@
import { Article } from "../../models/Article";
import { requireRole } from "../../utils/auth";
export default defineEventHandler(async (event) => {
const slug = getRouterParam(event, "slug");
// Only admins can delete articles
const user = await requireRole(event, ["admin"]);
if (!slug) {
throw createError({
statusCode: 400,
statusMessage: "Slug is required",
});
}
// Find and delete article
const article = await Article.findOneAndDelete({ slug });
if (!article) {
throw createError({
statusCode: 404,
statusMessage: "Article not found",
});
}
return {
success: true,
message: "Article deleted successfully",
};
});

View file

@ -0,0 +1,71 @@
import { Article } from '../../models/Article'
import { checkAccessLevel, verifyAuth } from '../../utils/auth'
export default defineEventHandler(async (event) => {
const slug = getRouterParam(event, 'slug')
if (!slug) {
throw createError({
statusCode: 400,
statusMessage: 'Slug is required'
})
}
// Find article
const article = await Article.findOne({ slug })
.populate('author', 'username displayName avatar')
.populate('contributors', 'username displayName avatar')
if (!article) {
throw createError({
statusCode: 404,
statusMessage: 'Article not found'
})
}
// Check access
const hasAccess = await checkAccessLevel(
event,
article.accessLevel,
article.cohorts
)
if (!hasAccess) {
// For protected content, return limited preview
if (article.accessLevel !== 'admin') {
return {
slug: article.slug,
title: article.title,
description: article.description.substring(0, 200) + '...',
category: article.category,
tags: article.tags,
accessLevel: article.accessLevel,
restricted: true,
message: 'This content requires authentication'
}
}
throw createError({
statusCode: 403,
statusMessage: 'Access denied'
})
}
// Increment view count
article.views += 1
await article.save()
// Get user to check if they've liked
const user = await verifyAuth(event)
const userLiked = false // TODO: Implement likes tracking
return {
...article.toObject(),
userLiked,
revisionCount: article.revisions.length,
commentCount: article.comments.length,
// Don't send full revisions and comments in main response
revisions: undefined,
comments: undefined
}
})

View file

@ -0,0 +1,109 @@
import { Article } from "../../models/Article";
import { requireAuth } from "../../utils/auth";
import { Types } from "mongoose";
export default defineEventHandler(async (event) => {
const slug = getRouterParam(event, "slug");
const user = await requireAuth(event);
const body = await readBody(event);
if (!slug) {
throw createError({
statusCode: 400,
statusMessage: "Slug is required",
});
}
// Find article
const article = await Article.findOne({ slug });
if (!article) {
throw createError({
statusCode: 404,
statusMessage: "Article not found",
});
}
// Check permissions
const isAuthor = article.author.toString() === user.userId;
const isAdmin = user.permissions.canAdmin;
const isModerator = user.permissions.canModerate;
const canEdit = user.permissions.canEdit;
if (!isAuthor && !isAdmin && !isModerator) {
throw createError({
statusCode: 403,
statusMessage: "You do not have permission to edit this article",
});
}
// Check if article is locked by another user
if (article.lockedBy && article.lockedBy.toString() !== user.userId) {
const lockExpired =
article.lockedAt &&
new Date().getTime() - article.lockedAt.getTime() > 30 * 60 * 1000; // 30 minutes
if (!lockExpired) {
throw createError({
statusCode: 423,
statusMessage: "Article is currently being edited by another user",
});
}
}
// Update fields
if (body.title) article.title = body.title;
if (body.description) article.description = body.description;
if (body.content) {
// Add to revision history
article.revisions.push({
content: body.content,
author: new Types.ObjectId(user.userId),
message: body.revisionMessage || "Content updated",
createdAt: new Date(),
});
article.content = body.content;
}
if (body.category) article.category = body.category;
if (body.tags) article.tags = body.tags;
if (body.accessLevel && (isAdmin || isModerator)) {
article.accessLevel = body.accessLevel;
}
if (body.cohorts && (isAdmin || isModerator)) {
article.cohorts = body.cohorts;
}
if (body.status) {
article.status = body.status;
if (body.status === "published" && !article.publishedAt) {
article.publishedAt = new Date();
}
}
// Add contributor if not already listed
const userObjectId = new Types.ObjectId(user.userId);
if (!article.contributors.some((c: any) => c.toString() === user.userId)) {
article.contributors.push(userObjectId);
}
// Clear lock
article.lockedBy = undefined;
article.lockedAt = undefined;
// Save changes
try {
await article.save();
return {
success: true,
slug: article.slug,
message: "Article updated successfully",
revision: article.revisions.length,
};
} catch (error) {
console.error("Error updating article:", error);
throw createError({
statusCode: 500,
statusMessage: "Failed to update article",
});
}
});

View file

@ -0,0 +1,76 @@
import { Article } from '../../models/Article'
import { checkAccessLevel } from '../../utils/auth'
export default defineEventHandler(async (event) => {
const query = getQuery(event)
// Pagination
const page = parseInt(query.page as string) || 1
const limit = parseInt(query.limit as string) || 20
const skip = (page - 1) * limit
// Build filter
const filter: any = { status: 'published' }
// Category filter
if (query.category) {
filter.category = query.category
}
// Tags filter
if (query.tags) {
const tags = (query.tags as string).split(',')
filter.tags = { $in: tags }
}
// Search filter
if (query.search) {
filter.$or = [
{ title: { $regex: query.search, $options: 'i' } },
{ description: { $regex: query.search, $options: 'i' } },
{ content: { $regex: query.search, $options: 'i' } }
]
}
// Get articles
const articles = await Article.find(filter)
.populate('author', 'username displayName avatar')
.select('-content -revisions -comments')
.sort({ publishedAt: -1 })
.skip(skip)
.limit(limit)
// Filter by access level
const filteredArticles = []
for (const article of articles) {
const hasAccess = await checkAccessLevel(
event,
article.accessLevel,
article.cohorts
)
if (hasAccess) {
filteredArticles.push(article)
} else if (article.accessLevel === 'member' || article.accessLevel === 'cohort') {
// Show preview for protected content
filteredArticles.push({
...article.toObject(),
description: article.description.substring(0, 200) + '...',
restricted: true
})
}
}
// Get total count
const total = await Article.countDocuments(filter)
return {
articles: filteredArticles,
pagination: {
page,
limit,
total,
pages: Math.ceil(total / limit)
}
}
})

View file

@ -0,0 +1,71 @@
import { Article } from '../../models/Article'
import { requireAuth } from '../../utils/auth'
export default defineEventHandler(async (event) => {
// Require authentication
const user = await requireAuth(event)
// Check if user can create articles
if (!user.permissions.canEdit) {
throw createError({
statusCode: 403,
statusMessage: 'You do not have permission to create articles'
})
}
// Get request body
const body = await readBody(event)
// Validate required fields
if (!body.title || !body.slug || !body.content) {
throw createError({
statusCode: 400,
statusMessage: 'Title, slug, and content are required'
})
}
// Check if slug already exists
const existing = await Article.findOne({ slug: body.slug })
if (existing) {
throw createError({
statusCode: 409,
statusMessage: 'An article with this slug already exists'
})
}
// Create article
try {
const article = await Article.create({
slug: body.slug,
title: body.title,
description: body.description || '',
content: body.content,
category: body.category || 'general',
tags: body.tags || [],
accessLevel: body.accessLevel || 'member',
cohorts: body.cohorts || [],
author: user.userId,
status: body.status || 'draft',
publishedAt: body.status === 'published' ? new Date() : null,
revisions: [{
content: body.content,
author: user.userId,
message: 'Initial creation',
createdAt: new Date()
}]
})
return {
success: true,
slug: article.slug,
message: 'Article created successfully'
}
} catch (error) {
console.error('Error creating article:', error)
throw createError({
statusCode: 500,
statusMessage: 'Failed to create article'
})
}
})

View file

@ -0,0 +1,100 @@
import { User } from "../../models/User";
import jwt from "jsonwebtoken";
import type {
OAuthTokenResponse,
GhostGuildUserInfo,
} from "../../../types/auth";
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig();
const query = getQuery(event);
// Verify state for CSRF protection
const storedState = getCookie(event, "oauth_state");
if (!storedState || storedState !== query.state) {
return sendRedirect(event, "/login?error=invalid_state");
}
// Clear the state cookie
deleteCookie(event, "oauth_state");
// Exchange authorization code for access token
try {
const tokenResponse = await $fetch<OAuthTokenResponse>(
`${config.ghostguildApiUrl}/oauth/token`,
{
method: "POST",
body: {
grant_type: "authorization_code",
code: query.code,
redirect_uri: `${config.public.siteUrl}/api/auth/callback`,
client_id: config.ghostguildClientId,
client_secret: config.ghostguildClientSecret,
},
},
);
// Get user information from Ghost Guild
const userInfo = await $fetch<GhostGuildUserInfo>(
`${config.ghostguildApiUrl}/user/me`,
{
headers: {
Authorization: `Bearer ${tokenResponse.access_token}`,
},
},
);
// Find or create user in our database
let user = await User.findOne({ ghostguildId: userInfo.id });
if (!user) {
user = await User.create({
ghostguildId: userInfo.id,
email: userInfo.email,
username: userInfo.username,
displayName: userInfo.displayName || userInfo.username,
avatar: userInfo.avatar,
roles: userInfo.roles || ["member"],
permissions: {
canEdit: userInfo.roles?.includes("member") || false,
canModerate: userInfo.roles?.includes("moderator") || false,
canAdmin: userInfo.roles?.includes("admin") || false,
},
lastLogin: new Date(),
});
} else {
// Update existing user
user.displayName = userInfo.displayName || userInfo.username;
user.avatar = userInfo.avatar;
user.roles = userInfo.roles || ["member"];
user.lastLogin = new Date();
await user.save();
}
// Create JWT token
const token = jwt.sign(
{
userId: user._id,
username: user.username,
roles: user.roles,
permissions: user.permissions,
},
config.jwtSecret as string,
{ expiresIn: "7d" },
);
// Set JWT as httpOnly cookie
setCookie(event, "auth-token", token, {
httpOnly: true,
secure: true,
sameSite: "lax",
maxAge: 60 * 60 * 24 * 7, // 7 days
});
// Redirect to dashboard or home
return sendRedirect(event, "/dashboard");
} catch (error) {
console.error("OAuth callback error:", error);
return sendRedirect(event, "/login?error=authentication_failed");
}
});

View file

@ -0,0 +1,28 @@
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig();
// Generate state for CSRF protection
const state = Math.random().toString(36).substring(7);
// Store state in session (you'll need to implement session storage)
setCookie(event, "oauth_state", state, {
httpOnly: true,
secure: true,
sameSite: "lax",
maxAge: 60 * 10, // 10 minutes
});
// Build OAuth authorization URL
const params = new URLSearchParams({
client_id: String(config.ghostguildClientId || ""),
redirect_uri: `${config.public.siteUrl}/api/auth/callback`,
response_type: "code",
scope: "read:user read:member",
state: state,
});
const authUrl = `${config.ghostguildApiUrl}/oauth/authorize?${params}`;
// Redirect to Ghost Guild OAuth
return sendRedirect(event, authUrl);
});

View file

@ -0,0 +1,10 @@
export default defineEventHandler(async (event) => {
// Clear the auth token cookie
deleteCookie(event, 'auth-token')
// Return success response
return {
success: true,
message: 'Logged out successfully'
}
})

View file

@ -0,0 +1,53 @@
import jwt from "jsonwebtoken";
import { User } from "../../models/User";
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig();
const token = getCookie(event, "auth-token");
if (!token) {
throw createError({
statusCode: 401,
statusMessage: "Unauthorized - No token provided",
});
}
try {
// Verify and decode the token
const decoded = jwt.verify(token, config.jwtSecret as string) as any;
// Get fresh user data from database
const user = await User.findById(decoded.userId).select("-__v");
if (!user) {
throw createError({
statusCode: 404,
statusMessage: "User not found",
});
}
// Return user data (without sensitive fields)
return {
id: user._id,
username: user.username,
displayName: user.displayName,
email: user.email,
avatar: user.avatar,
roles: user.roles,
permissions: user.permissions,
contributions: user.contributions,
};
} catch (error: any) {
if (
error.name === "JsonWebTokenError" ||
error.name === "TokenExpiredError"
) {
deleteCookie(event, "auth-token");
throw createError({
statusCode: 401,
statusMessage: "Invalid or expired token",
});
}
throw error;
}
});

View file

@ -0,0 +1,32 @@
import mongoose from 'mongoose'
export default defineEventHandler(async (event) => {
const checks = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
mongodb: 'disconnected',
memory: process.memoryUsage(),
}
// Check MongoDB connection
try {
if (mongoose.connection.readyState === 1) {
checks.mongodb = 'connected'
} else {
checks.mongodb = 'disconnected'
}
} catch (error) {
checks.mongodb = 'error'
}
// Return 503 if any critical service is down
const isHealthy = checks.mongodb === 'connected'
if (!isHealthy) {
setResponseStatus(event, 503)
checks.status = 'unhealthy'
}
return checks
})

View file

@ -0,0 +1,111 @@
import { Schema, model, Document, Types } from 'mongoose'
export interface IRevision {
content: string
author: Types.ObjectId
message: string
createdAt: Date
}
export interface IComment {
author: Types.ObjectId
content: string
parentComment?: Types.ObjectId
createdAt: Date
updatedAt: Date
resolved: boolean
}
export interface IArticle extends Document {
slug: string
title: string
description: string
content: string // Current content in markdown
category: string
tags: string[]
// Access control
accessLevel: 'public' | 'member' | 'cohort' | 'admin'
cohorts?: string[] // Specific cohorts if accessLevel is 'cohort'
// Metadata
author: Types.ObjectId
contributors: Types.ObjectId[]
views: number
likes: number
// Editing
status: 'draft' | 'published' | 'archived'
lockedBy?: Types.ObjectId // If someone is currently editing
lockedAt?: Date
// History
revisions: IRevision[]
comments: IComment[]
// Timestamps
createdAt: Date
updatedAt: Date
publishedAt?: Date
}
const revisionSchema = new Schema<IRevision>({
content: { type: String, required: true },
author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
message: { type: String, required: true },
createdAt: { type: Date, default: Date.now }
})
const commentSchema = new Schema<IComment>({
author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
content: { type: String, required: true },
parentComment: { type: Schema.Types.ObjectId, ref: 'Comment' },
resolved: { type: Boolean, default: false }
}, {
timestamps: true
})
const articleSchema = new Schema<IArticle>({
slug: { type: String, required: true, unique: true },
title: { type: String, required: true },
description: { type: String, required: true },
content: { type: String, required: true },
category: { type: String, required: true },
tags: [{ type: String }],
accessLevel: {
type: String,
enum: ['public', 'member', 'cohort', 'admin'],
default: 'member'
},
cohorts: [{ type: String }],
author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
contributors: [{ type: Schema.Types.ObjectId, ref: 'User' }],
views: { type: Number, default: 0 },
likes: { type: Number, default: 0 },
status: {
type: String,
enum: ['draft', 'published', 'archived'],
default: 'draft'
},
lockedBy: { type: Schema.Types.ObjectId, ref: 'User' },
lockedAt: Date,
revisions: [revisionSchema],
comments: [commentSchema],
publishedAt: Date
}, {
timestamps: true
})
// Indexes for better query performance
articleSchema.index({ slug: 1 })
articleSchema.index({ accessLevel: 1, status: 1 })
articleSchema.index({ tags: 1 })
articleSchema.index({ category: 1 })
articleSchema.index({ author: 1 })
export const Article = model<IArticle>('Article', articleSchema)

47
app/server/models/User.ts Normal file
View file

@ -0,0 +1,47 @@
import { Schema, model, Document } from 'mongoose'
export interface IUser extends Document {
ghostguildId: string // ID from ghostguild-org
email: string
username: string
displayName: string
avatar?: string
roles: string[] // 'admin', 'moderator', 'member', 'cohort-X'
permissions: {
canEdit: boolean
canModerate: boolean
canAdmin: boolean
}
contributions: {
edits: number
comments: number
articles: number
}
createdAt: Date
updatedAt: Date
lastLogin: Date
}
const userSchema = new Schema<IUser>({
ghostguildId: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
username: { type: String, required: true, unique: true },
displayName: { type: String, required: true },
avatar: String,
roles: [{ type: String }],
permissions: {
canEdit: { type: Boolean, default: false },
canModerate: { type: Boolean, default: false },
canAdmin: { type: Boolean, default: false }
},
contributions: {
edits: { type: Number, default: 0 },
comments: { type: Number, default: 0 },
articles: { type: Number, default: 0 }
},
lastLogin: { type: Date, default: Date.now }
}, {
timestamps: true
})
export const User = model<IUser>('User', userSchema)

View file

@ -0,0 +1,20 @@
import mongoose from "mongoose";
export default defineNitroPlugin(async () => {
const config = useRuntimeConfig();
try {
await mongoose.connect(config.mongodbUri as string);
console.log("✓ MongoDB connected successfully");
} catch (error) {
console.error("✗ MongoDB connection error:", error);
throw error;
}
// Graceful shutdown
process.on("SIGINT", async () => {
await mongoose.connection.close();
console.log("MongoDB connection closed");
process.exit(0);
});
});

View file

@ -0,0 +1,91 @@
/**
* Wikilink Transformation Plugin
*
* Transforms Obsidian wikilink syntax to standard markdown links at build time.
* Handles:
* - [[Page Title]] [Page Title](/articles/page-title)
* - [[Page|Display Text]] [Display Text](/articles/page)
* - ![[image.jpg]] ![image.jpg](/img/image.jpg)
* - ![[image.jpg|alt text]] ![alt text](/img/image.jpg)
*
* Runs during content:file:beforeParse hook for early transformation
*/
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('content:file:beforeParse' as any, (file: any) => {
// Only process markdown files in articles collection
if (file._id && file._id.endsWith('.md') && file._id.includes('/articles/')) {
if (file.body) {
file.body = transformWikilinks(file.body);
file.body = transformImageEmbeds(file.body);
}
}
});
});
/**
* Transform Obsidian wikilinks to markdown links
* Patterns:
* - [[P0 - Page Title]]
* - [[Page Title|Display Text]]
* - [[P1 - Long Title|Short]]
*/
function transformWikilinks(content: string): string {
// Pattern: [[P0/P1/P2 - Page Title]] or [[Page Title]] with optional |Display Text
const wikilinkPattern = /\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g;
return content.replace(wikilinkPattern, (match, pageName, displayText) => {
// Clean the page name: strip P0/P1/P2 prefix
const cleanName = pageName.replace(/^P[012]\s*-\s*/i, '').trim();
// Generate slug from clean name
const slug = titleToSlug(cleanName);
// Use display text if provided, otherwise use clean name
const linkText = displayText ? displayText.trim() : cleanName;
// Generate markdown link with /articles/ prefix
return `[${linkText}](/articles/${slug})`;
});
}
/**
* Transform Obsidian image embeds to markdown image syntax
* Patterns:
* - ![[image.jpg]]
* - ![[image.jpg|alt text]]
*/
function transformImageEmbeds(content: string): string {
// Pattern: ![[filename]] or ![[filename|alt text]]
const imagePattern = /!\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g;
return content.replace(imagePattern, (match, filename, altText) => {
// Use alt text if provided, otherwise use filename (without extension)
const alt = altText?.trim() || filename.replace(/\.(jpg|jpeg|png|gif|svg|webp)$/i, '');
// Generate markdown image syntax with /img/ prefix
return `![${alt}](/img/${filename})`;
});
}
/**
* Convert a page title to a URL slug
* Rules:
* 1. Convert to lowercase
* 2. Remove quotation marks
* 3. Replace & with "and"
* 4. Remove other special characters (keep alphanumeric and hyphens)
* 5. Replace spaces with hyphens
* 6. Collapse multiple hyphens to single hyphen
* 7. Trim hyphens from start/end
*/
function titleToSlug(title: string): string {
return title
.toLowerCase()
.replace(/['"]/g, '') // Remove quotes
.replace(/&/g, 'and') // & → and
.replace(/[^a-z0-9\s-]/g, '') // Remove special characters
.replace(/\s+/g, '-') // Spaces → hyphens
.replace(/-+/g, '-') // Collapse multiple hyphens
.replace(/^-|-$/g, ''); // Trim hyphens from edges
}

3
app/server/tsconfig.json Normal file
View file

@ -0,0 +1,3 @@
{
"extends": "../.nuxt/tsconfig.server.json"
}

12
app/server/types.d.ts vendored Normal file
View file

@ -0,0 +1,12 @@
declare module "nitropack" {
interface NitroRuntimeConfig {
mongodbUri: string;
jwtSecret: string;
ghostguildApiUrl: string;
ghostguildApiKey: string;
ghostguildClientId: string;
ghostguildClientSecret: string;
}
}
export {};

100
app/server/utils/auth.ts Normal file
View file

@ -0,0 +1,100 @@
import jwt from "jsonwebtoken";
import type { H3Event } from "h3";
import { User } from "../models/User";
export interface AuthUser {
userId: string;
username: string;
roles: string[];
permissions: {
canEdit: boolean;
canModerate: boolean;
canAdmin: boolean;
};
}
export async function verifyAuth(event: H3Event): Promise<AuthUser | null> {
const config = useRuntimeConfig();
const token = getCookie(event, "auth-token");
if (!token) {
return null;
}
try {
const decoded = jwt.verify(token, config.jwtSecret as string) as AuthUser;
return decoded;
} catch (error) {
return null;
}
}
export async function requireAuth(event: H3Event): Promise<AuthUser> {
const user = await verifyAuth(event);
if (!user) {
throw createError({
statusCode: 401,
statusMessage: "Authentication required",
});
}
return user;
}
export async function requireRole(
event: H3Event,
requiredRoles: string[],
): Promise<AuthUser> {
const user = await requireAuth(event);
const hasRole = requiredRoles.some((role) => user.roles.includes(role));
if (!hasRole) {
throw createError({
statusCode: 403,
statusMessage: "Insufficient permissions",
});
}
return user;
}
export async function checkAccessLevel(
event: H3Event,
accessLevel: "public" | "member" | "cohort" | "admin",
cohorts?: string[],
): Promise<boolean> {
// Public content is always accessible
if (accessLevel === "public") {
return true;
}
const user = await verifyAuth(event);
// No user = no access to protected content
if (!user) {
return false;
}
// Check access levels
switch (accessLevel) {
case "member":
// Any authenticated user has member access
return true;
case "cohort":
// Check if user belongs to required cohorts
if (!cohorts || cohorts.length === 0) {
return true; // No specific cohort required
}
return cohorts.some((cohort) => user.roles.includes(`cohort-${cohort}`));
case "admin":
// Only admins have admin access
return user.permissions.canAdmin || user.roles.includes("admin");
default:
return false;
}
}

46
app/types/auth.ts Normal file
View file

@ -0,0 +1,46 @@
export interface User {
id: string;
username: string;
displayName: string;
email: string;
avatar?: string;
roles: string[];
permissions: {
canEdit: boolean;
canModerate: boolean;
canAdmin: boolean;
};
contributions: {
articles: number;
edits: number;
comments: number;
};
}
export interface AuthUser {
userId: string;
username: string;
roles: string[];
permissions: {
canEdit: boolean;
canModerate: boolean;
canAdmin: boolean;
};
}
export interface OAuthTokenResponse {
access_token: string;
token_type: string;
expires_in: number;
refresh_token?: string;
scope?: string;
}
export interface GhostGuildUserInfo {
id: string;
email: string;
username: string;
displayName?: string;
avatar?: string;
roles?: string[];
}

23
content.config.ts Normal file
View file

@ -0,0 +1,23 @@
import { defineContentConfig, defineCollection } from "@nuxt/content";
import { z } from "zod";
export default defineContentConfig({
collections: {
articles: defineCollection({
type: "data",
source: "**/*.md",
schema: z.object({
title: z.string(),
description: z.string().optional(),
category: z.string().optional(),
tags: z.array(z.string()).optional(),
author: z.string().optional(),
contributors: z.array(z.string()).optional(),
published: z.boolean().default(true),
featured: z.boolean().default(false),
accessLevel: z.string().optional(),
publishedAt: z.string().optional(),
}),
}),
},
});

1
content/.obsidian/app.json vendored Normal file
View file

@ -0,0 +1 @@
{}

1
content/.obsidian/appearance.json vendored Normal file
View file

@ -0,0 +1 @@
{}

33
content/.obsidian/core-plugins.json vendored Normal file
View file

@ -0,0 +1,33 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}

181
content/.obsidian/workspace.json vendored Normal file
View file

@ -0,0 +1,181 @@
{
"main": {
"id": "10742e87f1722b56",
"type": "split",
"children": [
{
"id": "74737af76d9833e3",
"type": "tabs",
"children": [
{
"id": "e236d1a919bfe851",
"type": "leaf",
"state": {
"type": "empty",
"state": {},
"icon": "lucide-file",
"title": "New tab"
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "ca15da42ce91c312",
"type": "split",
"children": [
{
"id": "63cf54e8ed8b0f8c",
"type": "tabs",
"children": [
{
"id": "0c4bc1ae471bb8d4",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false
},
"icon": "lucide-folder-closed",
"title": "Files"
}
},
{
"id": "14073c50a39cba51",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
},
"icon": "lucide-search",
"title": "Search"
}
},
{
"id": "1dbdde24934bc48c",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {},
"icon": "lucide-bookmark",
"title": "Bookmarks"
}
}
]
}
],
"direction": "horizontal",
"width": 300
},
"right": {
"id": "22d64e9fe85def54",
"type": "split",
"children": [
{
"id": "75870d504b82d583",
"type": "tabs",
"children": [
{
"id": "b79738e65fbc31e7",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "Backlinks"
}
},
{
"id": "c6ebfc3793c40206",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "Outgoing links"
}
},
{
"id": "09c0daad51bc0936",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-tags",
"title": "Tags"
}
},
{
"id": "89c1c2af18fcc7c1",
"type": "leaf",
"state": {
"type": "all-properties",
"state": {
"sortOrder": "frequency",
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-archive",
"title": "All properties"
}
},
{
"id": "cf4d80a6d65d3399",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "Outline"
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"left-ribbon": {
"hiddenItems": {
"switcher:Open quick switcher": false,
"graph:Open graph view": false,
"canvas:Create new canvas": false,
"daily-notes:Open today's daily note": false,
"templates:Insert template": false,
"command-palette:Open command palette": false,
"bases:Create new base": false
}
},
"active": "e236d1a919bfe851",
"lastOpenFiles": []
}

69
content/articles/.obsidian/app.json vendored Normal file
View file

@ -0,0 +1,69 @@
{
"baseTheme": "dark",
"attachmentFolderPath": "../../public/img",
"newFileLocation": "current",
"newFileFolderPath": "./",
"useMarkdownLinks": false,
"insideBlockLink": false,
"alwaysUpdateLinks": true,
"autoRunCommand": "",
"autoPairBrackets": true,
"autoPairMarkdown": true,
"autoCreateBracketLinkNote": false,
"enableConsoleCheckbox": false,
"enableFolderColors": true,
"defaultViewMode": "preview",
"livePreview": true,
"strictLineBreaks": false,
"showLineNumber": true,
"showFrontmatter": false,
"showUnsupportedFiles": true,
"promptDelete": true,
"useTab": true,
"tabSize": 2,
"useIndentedTransclusion": false,
"fileSortOrder": "alphabetical",
"lineWrapByDefault": false,
"readableLineLength": true,
"rightToLeft": false,
"command": "",
"focusNewTab": true,
"spellcheck": true,
"spellcheckLanguages": [
"en-US"
],
"longLineBreak": false,
"plaintext": false,
"showFoldInfo": true,
"focusOnTabChange": false,
"alwaysUpdateLinksOnChange": false,
"updateLinkOnFileMove": true,
"collapseFolders": false,
"enableAutoMetadata": false,
"properties": {
"inherited": false
},
"urlEngineParameters": "{}",
"toggleCheckedSyntax": "- [ ]",
"foldHeading": true,
"foldIndent": true,
"showEmojiPicker": true,
"vimMode": false,
"maximizeTransclusion": false,
"openMDLinksInMarkdownView": true,
"showFileOutline": true,
"showZoomLevel": false,
"maxTitleLength": 0,
"arcanaVolume": 0.5,
"arcanaEnabled": true,
"legacyEditor": false,
"livePreviewDisplayRes": 1,
"inlineBacklinks": true,
"backupOnSave": false,
"backupCount": 10,
"autoSaveInterval": 0,
"trashOption": "system",
"showImagesInlineExternal": false,
"workspaceWidth": 1440,
"workspaceClosed": false
}

View file

@ -0,0 +1,6 @@
{
"baseFontSize": 16,
"cssTheme": "Minimal",
"translucency": false,
"enabledCssSnippets": []
}

View file

@ -0,0 +1,5 @@
[
"obsidian-git",
"linter",
"templater-obsidian"
]

View file

@ -0,0 +1,33 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}

20
content/articles/.obsidian/hotkeys.json vendored Normal file
View file

@ -0,0 +1,20 @@
{
"obsidian-git:commit": [
{
"modifiers": ["Mod", "Shift"],
"key": "g"
}
],
"obsidian-git:push": [
{
"modifiers": ["Mod", "Shift", "Alt"],
"key": "g"
}
],
"obsidian-git:pull": [
{
"modifiers": ["Mod", "Shift", "Control"],
"key": "g"
}
]
}

View file

@ -0,0 +1,73 @@
{
"commitMessage": "vault backup: {{date}}",
"autoCommitMessage": "vault backup: {{date}}",
"commitMessageScript": "",
"commitDateFormat": "YYYY-MM-DD HH:mm:ss",
"autoSaveInterval": 0,
"autoPushInterval": 0,
"autoPullInterval": 5,
"autoPullOnBoot": true,
"autoCommitOnlyStaged": false,
"disablePush": false,
"pullBeforePush": true,
"disablePopups": false,
"showErrorNotices": true,
"disablePopupsForNoChanges": false,
"listChangedFilesInMessageBody": false,
"showStatusBar": true,
"updateSubmodules": false,
"syncMethod": "merge",
"customMessageOnAutoBackup": false,
"autoBackupAfterFileChange": false,
"treeStructure": false,
"refreshSourceControl": true,
"basePath": "",
"differentIntervalCommitAndPush": false,
"changedFilesInStatusBar": false,
"showedMobileNotice": false,
"refreshSourceControlTimer": 7000,
"showBranchStatusBar": true,
"setLastSaveToLastCommit": false,
"submoduleRecurseCheckout": false,
"gitDir": "",
"showFileMenu": true,
"authorInHistoryView": "hide",
"dateInHistoryView": false,
"diffStyle": "split",
"lineAuthor": {
"show": false,
"followMovement": "inactive",
"authorDisplay": "initials",
"showCommitHash": false,
"dateTimeFormatOptions": "date",
"dateTimeFormatCustomString": "YYYY-MM-DD HH:mm",
"dateTimeTimezone": "viewer-local",
"coloringMaxAge": "1y",
"colorNew": {
"r": 255,
"g": 150,
"b": 150
},
"colorOld": {
"r": 120,
"g": 160,
"b": 255
},
"textColorCss": "var(--text-muted)",
"ignoreWhitespace": false,
"gutterSpacingFallbackLength": 5
},
"autoCommit": false,
"autoSaveOnFocusChange": false,
"conflictHandlingStrategy": "ask",
"customBackupMessage": "backup",
"showDesktopNotification": true,
"listChangedFilesInPullRequest": false,
"showCachedOnly": false,
"showFileHistoryComments": false,
"showFileHistoryCommentContextLines": 0,
"disableHistoryView": false,
"showIgnoreFiles": false,
"showDesktopNotifications": true,
"splitDirection": "horizontal"
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
{
"author": "Vinzent",
"authorUrl": "https://github.com/Vinzent03",
"id": "obsidian-git",
"name": "Git",
"description": "Integrate Git version control with automatic backup and other advanced features.",
"isDesktopOnly": false,
"fundingUrl": "https://ko-fi.com/vinzent",
"version": "2.35.2"
}

View file

@ -0,0 +1,23 @@
#!/bin/sh
PROMPT="$1"
TEMP_FILE="$OBSIDIAN_GIT_CREDENTIALS_INPUT"
cleanup() {
rm -f "$TEMP_FILE" "$TEMP_FILE.response"
}
trap cleanup EXIT
echo "$PROMPT" > "$TEMP_FILE"
while [ ! -e "$TEMP_FILE.response" ]; do
if [ ! -e "$TEMP_FILE" ]; then
echo "Trigger file got removed: Abort" >&2
exit 1
fi
sleep 0.1
done
RESPONSE=$(cat "$TEMP_FILE.response")
echo "$RESPONSE"

View file

@ -0,0 +1,629 @@
@keyframes loading {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.workspace-leaf-content[data-type="git-view"] .button-border {
border: 2px solid var(--interactive-accent);
border-radius: var(--radius-s);
}
.workspace-leaf-content[data-type="git-view"] .view-content {
padding-left: 0;
padding-top: 0;
padding-right: 0;
}
.workspace-leaf-content[data-type="git-history-view"] .view-content {
padding-left: 0;
padding-top: 0;
padding-right: 0;
}
.loading {
overflow: hidden;
}
.loading > svg {
animation: 2s linear infinite loading;
transform-origin: 50% 50%;
display: inline-block;
}
.obsidian-git-center {
margin: auto;
text-align: center;
width: 50%;
}
.obsidian-git-textarea {
display: block;
margin-left: auto;
margin-right: auto;
}
.obsidian-git-disabled {
opacity: 0.5;
}
.obsidian-git-center-button {
display: block;
margin: 20px auto;
}
.tooltip.mod-left {
overflow-wrap: break-word;
}
.tooltip.mod-right {
overflow-wrap: break-word;
}
/* Limits the scrollbar to the view body */
.git-view {
display: flex;
flex-direction: column;
position: relative;
height: 100%;
}
.git-tools {
display: flex;
margin-left: auto;
}
.git-tools .type {
padding-left: var(--size-2-1);
display: flex;
align-items: center;
justify-content: center;
width: 11px;
}
.git-tools .type[data-type="M"] {
color: orange;
}
.git-tools .type[data-type="D"] {
color: red;
}
.git-tools .buttons {
display: flex;
}
.git-tools .buttons > * {
padding: 0 0;
height: auto;
}
.workspace-leaf-content[data-type="git-view"] .tree-item-self,
.workspace-leaf-content[data-type="git-history-view"] .tree-item-self {
align-items: center;
}
.workspace-leaf-content[data-type="git-view"]
.tree-item-self:hover
.clickable-icon,
.workspace-leaf-content[data-type="git-history-view"]
.tree-item-self:hover
.clickable-icon {
color: var(--icon-color-hover);
}
/* Highlight an item as active if it's diff is currently opened */
.is-active .git-tools .buttons > * {
color: var(--nav-item-color-active);
}
.git-author {
color: var(--text-accent);
}
.git-date {
color: var(--text-accent);
}
.git-ref {
color: var(--text-accent);
}
.workspace-leaf-content[data-type="diff-view"] .d2h-d-none {
display: none;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-wrapper {
text-align: left;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-header {
background-color: var(--background-primary);
border-bottom: 1px solid var(--interactive-accent);
font-family: var(--font-monospace);
height: 35px;
padding: 5px 10px;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-header,
.workspace-leaf-content[data-type="diff-view"] .d2h-file-stats {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-stats {
font-size: 14px;
margin-left: auto;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-lines-added {
border: 1px solid #b4e2b4;
border-radius: 5px 0 0 5px;
color: #399839;
padding: 2px;
text-align: right;
vertical-align: middle;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-lines-deleted {
border: 1px solid #e9aeae;
border-radius: 0 5px 5px 0;
color: #c33;
margin-left: 1px;
padding: 2px;
text-align: left;
vertical-align: middle;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-name-wrapper {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
font-size: 15px;
width: 100%;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-name {
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-wrapper {
border: 1px solid var(--background-modifier-border);
border-radius: 3px;
margin-bottom: 1em;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-collapse {
-webkit-box-pack: end;
-ms-flex-pack: end;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
border: 1px solid var(--background-modifier-border);
border-radius: 3px;
cursor: pointer;
display: none;
font-size: 12px;
justify-content: flex-end;
padding: 4px 8px;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-collapse.d2h-selected {
background-color: #c8e1ff;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-collapse-input {
margin: 0 4px 0 0;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-diff-table {
border-collapse: collapse;
font-family: Menlo, Consolas, monospace;
font-size: 13px;
width: 100%;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-files-diff {
width: 100%;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-diff {
overflow-y: hidden;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-side-diff {
display: inline-block;
margin-bottom: -8px;
margin-right: -4px;
overflow-x: scroll;
overflow-y: hidden;
width: 50%;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-line {
padding: 0 8em;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-line,
.workspace-leaf-content[data-type="diff-view"] .d2h-code-side-line {
display: inline-block;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
white-space: nowrap;
width: 100%;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-side-line {
padding: 0 4.5em;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-line-ctn {
word-wrap: normal;
background: none;
display: inline-block;
padding: 0;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
vertical-align: middle;
white-space: pre;
width: 100%;
}
.theme-light .workspace-leaf-content[data-type="diff-view"] .d2h-code-line del,
.theme-light
.workspace-leaf-content[data-type="diff-view"]
.d2h-code-side-line
del {
background-color: #ffb6ba;
}
.theme-dark .workspace-leaf-content[data-type="diff-view"] .d2h-code-line del,
.theme-dark
.workspace-leaf-content[data-type="diff-view"]
.d2h-code-side-line
del {
background-color: #8d232881;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-line del,
.workspace-leaf-content[data-type="diff-view"] .d2h-code-line ins,
.workspace-leaf-content[data-type="diff-view"] .d2h-code-side-line del,
.workspace-leaf-content[data-type="diff-view"] .d2h-code-side-line ins {
border-radius: 0.2em;
display: inline-block;
margin-top: -1px;
text-decoration: none;
vertical-align: middle;
}
.theme-light .workspace-leaf-content[data-type="diff-view"] .d2h-code-line ins,
.theme-light
.workspace-leaf-content[data-type="diff-view"]
.d2h-code-side-line
ins {
background-color: #97f295;
text-align: left;
}
.theme-dark .workspace-leaf-content[data-type="diff-view"] .d2h-code-line ins,
.theme-dark
.workspace-leaf-content[data-type="diff-view"]
.d2h-code-side-line
ins {
background-color: #1d921996;
text-align: left;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-line-prefix {
word-wrap: normal;
background: none;
display: inline;
padding: 0;
white-space: pre;
}
.workspace-leaf-content[data-type="diff-view"] .line-num1 {
float: left;
}
.workspace-leaf-content[data-type="diff-view"] .line-num1,
.workspace-leaf-content[data-type="diff-view"] .line-num2 {
-webkit-box-sizing: border-box;
box-sizing: border-box;
overflow: hidden;
padding: 0 0.5em;
text-overflow: ellipsis;
width: 3.5em;
}
.workspace-leaf-content[data-type="diff-view"] .line-num2 {
float: right;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-linenumber {
background-color: var(--background-primary);
border: solid var(--background-modifier-border);
border-width: 0 1px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: var(--text-muted);
cursor: pointer;
display: inline-block;
position: absolute;
text-align: right;
width: 7.5em;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-linenumber:after {
content: "\200b";
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-side-linenumber {
background-color: var(--background-primary);
border: solid var(--background-modifier-border);
border-width: 0 1px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: var(--text-muted);
cursor: pointer;
display: inline-block;
overflow: hidden;
padding: 0 0.5em;
position: absolute;
text-align: right;
text-overflow: ellipsis;
width: 4em;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-diff-tbody tr {
position: relative;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-side-linenumber:after {
content: "\200b";
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-side-emptyplaceholder,
.workspace-leaf-content[data-type="diff-view"] .d2h-emptyplaceholder {
background-color: var(--background-primary);
border-color: var(--background-modifier-border);
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-line-prefix,
.workspace-leaf-content[data-type="diff-view"] .d2h-code-linenumber,
.workspace-leaf-content[data-type="diff-view"] .d2h-code-side-linenumber,
.workspace-leaf-content[data-type="diff-view"] .d2h-emptyplaceholder {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-code-linenumber,
.workspace-leaf-content[data-type="diff-view"] .d2h-code-side-linenumber {
direction: rtl;
}
.theme-light .workspace-leaf-content[data-type="diff-view"] .d2h-del {
background-color: #fee8e9;
border-color: #e9aeae;
}
.theme-light .workspace-leaf-content[data-type="diff-view"] .d2h-ins {
background-color: #dfd;
border-color: #b4e2b4;
}
.theme-dark .workspace-leaf-content[data-type="diff-view"] .d2h-del {
background-color: #521b1d83;
border-color: #691d1d73;
}
.theme-dark .workspace-leaf-content[data-type="diff-view"] .d2h-ins {
background-color: rgba(30, 71, 30, 0.5);
border-color: #13501381;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-info {
background-color: var(--background-primary);
border-color: var(--background-modifier-border);
color: var(--text-normal);
}
.theme-light
.workspace-leaf-content[data-type="diff-view"]
.d2h-file-diff
.d2h-del.d2h-change {
background-color: #fdf2d0;
}
.theme-dark
.workspace-leaf-content[data-type="diff-view"]
.d2h-file-diff
.d2h-del.d2h-change {
background-color: #55492480;
}
.theme-light
.workspace-leaf-content[data-type="diff-view"]
.d2h-file-diff
.d2h-ins.d2h-change {
background-color: #ded;
}
.theme-dark
.workspace-leaf-content[data-type="diff-view"]
.d2h-file-diff
.d2h-ins.d2h-change {
background-color: rgba(37, 78, 37, 0.418);
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-list-wrapper {
margin-bottom: 10px;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-list-wrapper a {
color: #3572b0;
text-decoration: none;
}
.workspace-leaf-content[data-type="diff-view"]
.d2h-file-list-wrapper
a:visited {
color: #3572b0;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-list-header {
text-align: left;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-list-title {
font-weight: 700;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-list-line {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
text-align: left;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-list {
display: block;
list-style: none;
margin: 0;
padding: 0;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-list > li {
border-bottom: 1px solid var(--background-modifier-border);
margin: 0;
padding: 5px 10px;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-list > li:last-child {
border-bottom: none;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-file-switch {
cursor: pointer;
display: none;
font-size: 10px;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-icon {
fill: currentColor;
margin-right: 10px;
vertical-align: middle;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-deleted {
color: #c33;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-added {
color: #399839;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-changed {
color: #d0b44c;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-moved {
color: #3572b0;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-tag {
background-color: var(--background-primary);
display: -webkit-box;
display: -ms-flexbox;
display: flex;
font-size: 10px;
margin-left: 5px;
padding: 0 2px;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-deleted-tag {
border: 2px solid #c33;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-added-tag {
border: 1px solid #399839;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-changed-tag {
border: 1px solid #d0b44c;
}
.workspace-leaf-content[data-type="diff-view"] .d2h-moved-tag {
border: 1px solid #3572b0;
}
/* ====================== Line Authoring Information ====================== */
.cm-gutterElement.obs-git-blame-gutter {
/* Add background color to spacing inbetween and around the gutter for better aesthetics */
border-width: 0px 2px 0.2px 2px;
border-style: solid;
border-color: var(--background-secondary);
background-color: var(--background-secondary);
}
.cm-gutterElement.obs-git-blame-gutter > div,
.line-author-settings-preview {
/* delegate text color to settings */
color: var(--obs-git-gutter-text);
font-family: monospace;
height: 100%; /* ensure, that age-based background color occupies entire parent */
text-align: right;
padding: 0px 6px 0px 6px;
white-space: pre; /* Keep spaces and do not collapse them. */
}
@media (max-width: 800px) {
/* hide git blame gutter not to superpose text */
.cm-gutterElement.obs-git-blame-gutter {
display: none;
}
}
.git-unified-diff-view,
.git-split-diff-view .cm-deletedLine .cm-changedText {
background-color: #ee443330;
}
.git-unified-diff-view,
.git-split-diff-view .cm-insertedLine .cm-changedText {
background-color: #22bb2230;
}
.git-obscure-prompt[git-is-obscured="true"] #git-show-password:after {
-webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-eye"><path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"></path><circle cx="12" cy="12" r="3"></circle></svg>');
}
.git-obscure-prompt[git-is-obscured="false"] #git-show-password:after {
-webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-eye-off"><path d="M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"></path><path d="M14.084 14.158a3 3 0 0 1-4.242-4.242"></path><path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"></path><path d="m2 2 20 20"></path></svg>');
}
/* Override styling of Codemirror merge view "collapsed lines" indicator */
.git-split-diff-view .ͼ2 .cm-collapsedLines {
background: var(--interactive-normal);
border-radius: var(--radius-m);
color: var(--text-accent);
font-size: var(--font-small);
padding: var(--size-4-1) var(--size-4-1);
}
.git-split-diff-view .ͼ2 .cm-collapsedLines:hover {
background: var(--interactive-hover);
color: var(--text-accent-hover);
}

View file

@ -0,0 +1,206 @@
{
"main": {
"id": "3def0763f6d7af9c",
"type": "split",
"children": [
{
"id": "2f6eb446821d6623",
"type": "tabs",
"children": [
{
"id": "e9fb0ab9519305e2",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "actionable-steam-metrics.md",
"mode": "preview",
"source": false
},
"icon": "lucide-file",
"title": "actionable-steam-metrics"
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "9b78d1399971fa76",
"type": "split",
"children": [
{
"id": "07295bf0e8df7630",
"type": "tabs",
"children": [
{
"id": "d77fc4f9f41a5d89",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false
},
"icon": "lucide-folder-closed",
"title": "Files"
}
},
{
"id": "147106ace037d893",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
},
"icon": "lucide-search",
"title": "Search"
}
},
{
"id": "b506e861dd73995f",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {},
"icon": "lucide-bookmark",
"title": "Bookmarks"
}
}
]
}
],
"direction": "horizontal",
"width": 273.5
},
"right": {
"id": "3b5361ef0668d521",
"type": "split",
"children": [
{
"id": "ca01dc75da5a824a",
"type": "tabs",
"children": [
{
"id": "3301689b57b10d64",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "Backlinks"
}
},
{
"id": "5b82c13ba9fc821c",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "Outgoing links"
}
},
{
"id": "d2a230c73d75031c",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-tags",
"title": "Tags"
}
},
{
"id": "2f36aeed6c374ff4",
"type": "leaf",
"state": {
"type": "all-properties",
"state": {
"sortOrder": "frequency",
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-archive",
"title": "All properties"
}
},
{
"id": "dde602e7b0ba07df",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"file": "accessibility-guide-disability-in-game-development-studios.md",
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "Outline of accessibility-guide-disability-in-game-development-studios"
}
}
],
"currentTab": 4
}
],
"direction": "horizontal",
"width": 300
},
"left-ribbon": {
"hiddenItems": {
"switcher:Open quick switcher": false,
"graph:Open graph view": false,
"canvas:Create new canvas": false,
"daily-notes:Open today's daily note": false,
"templates:Insert template": false,
"command-palette:Open command palette": false,
"bases:Create new base": false,
"obsidian-git:Open Git source control": false
}
},
"active": "d77fc4f9f41a5d89",
"lastOpenFiles": [
"actionable-steam-metrics.md",
"accessibility-guide-disability-in-game-development-studios.md",
"schedule.md",
"self-assessment.md",
"stages-of-coop-development.md",
"structures-for-impact.md",
"studio-bylaws-governance-template.md",
"telling-your-story.md",
"tiktok-meeting-notes.md",
"expo-tips.md",
"business-planning.md",
"accessibility-guide-neurodiversity-in-game-development-studios.md",
"publishing-marketing-playbook-for-game-studios.md",
"regional-guide-game-development-in-atlantic-canada.md",
"process-development.md",
"financial-modelling.md",
"market-analysis.md",
"accessibility-guide-economic-accessibility-in-game-development.md"
]
}

View file

@ -0,0 +1,75 @@
---
title: Actionable Steam Metrics
description: ''
category: strategy
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.227Z'
---
# Actionable Steam metrics
_Jennie: I want to share some tips from a recent workshop at GamePlay Space on Steam metrics. I hope my notes are helpful!_
**Wednesday, Nov 9 with Alden Kroll (Valve)**
How to use reporting within Steam to make decisions as you deploy and ship your game.
### Understanding Steam data sites
Alden highlighted three main Steam portals that offer data on game performance:
|Portal|Description|
|---|---|
|**Sales and Activations Reports portal**|Your go-to once you have a store page for your game. It helps you track performance indicators like sales, players, and wishlists. Only useful once you have a store page for your game. _Provides a "near real-time view into revenue, units, player counts, geographic breakdown, and other statistics related to your product."_
|**Steamworks**|A handy tool for monitoring game traffic, visibility, and builds usage.|
|**Steam charts**|Offers a global perspective with charts, stats, and reports.|
### Pre-release data gathering
Pre-release is all about understanding the **potential audience** and the **market landscape**. Here are some things Alden recommended you pay attention to:
|Metric|Description|
|---|---|
|Hardware survey|Steam's platform-wide data can guide technical requirements, like screen resolution, languages, and hardware compatibility.|
|Tag pages|Use these for **market research**, identifying trends in successful games, their features, scope, qualities, price points, and presentation styles.|
|Wishlists|Key to **gauging awareness** and building an audience to engage upon release and during discounts. They can also provide platform-specific stats and indicate long-term growth trends. Lifetime conversion shows up after 3 months. Cohorts: long term cohort growth indicates price sensitive users waiting for a better deal.|
|Regional wishlists|Localization ideas can be drawn from regional wishlist data. To access this, head to sales and activations reports, select your game, and click on *Regional sales report*.|
|[UTM tracking](https://partner.steamgames.com/doc/marketing/utm_analytics)|This tool helps measure the impact of external marketing like streamer and press outreach. Chris Zukowski's guide on [how to use Steams UTM feature](https://howtomarketagame.com/2021/04/14/how-to-use-steams-utm-feature-to-track-the-number-of-wishlists-and-sales-your-marketing-is-generating/) was recommended for more info.|
|Steam playtest|The playtest feature can give you specific data about your potential audience, including hardware usage and regional player breakdown.|
|[Data articles](https://steamcommunity.com/groups/steamworks)|Keep an eye on Valve's occasional articles; they provide useful data on things like controller usage trends, wishlisting trends, and findings from events like NextFest.|
### Post-release metrics and analysis
Once the game is out, here are the metrics you should track:
|Metric|Description|
|---|---|
|Game sales data reports|Compare time periods, countries, and promotional events. _Use comparison tools to compare periods of time. Choose “preferences” and then choose time period._|
|Game player numbers|Metrics like concurrent players and daily active users show traction. _What are the effects of shipping updates?_|
|Median playtime|Track the average playtime to understand how long players are engaging with the game, and if there's a drop-off point you need to address.|
|Remote play stats|Monitor how many people are playing your game on other devices or via the *remote play together* feature. _To access: Sales and activations reports > Select your game > Click Remote Play Stats on the right_|
|Controller usage|Understand the input devices players are using, especially controllers. The Steam Input API can help ensure complete support for all devices.|
|Game hardware survey|A monthly survey sampling from players gives you details on hardware specs (CPU, GPU, OS, Memory, etc.). This is useful to ensure the game is compatible with the most common hardware.|
|Steam key activations|Shows where batches of keys are ending up and how many are being redeemed. _Note: once generated, you can't update tags on a batch. Break them down as much as you can._|
|Refund data|See the reasons and notes left by customers during refund. Can be useful to identify blocking issues for players _To access: Select a package for your game > Click Refund Data on right hand menu|
|User reviews|Not exactly a metric, but reviews offer a treasure trove of qualitative data about your game's performance and reception. Monitor and code them to identify trends and issues. There's an API call to get a full list if you wish to run your own analysis!|
|Events & announcements|Each post comes with visibility, open info, and voting data.|
|Promos and discounts|Analyze how players respond to different price points to optimize your discount strategy. Is there a sweet spot for discounting your game? Which events connect you best with players? Combine with reports previously mentioned to compare results. CSV includes base price and sale price so you can tell when its a discounted purchase. CSV exports available.|
|Traffic and visibility|Understand where your game appears on Steam and how players find it. What paths are players taking to find your game? See how visibility reacts to spikes in player interest. CSV export available.|
|Beta branch users|Track how many players opt into each branch of your game build. This can provide useful feedback on the stability of builds.|
|In-game purchases|If you're selling in-game items that can be traded or gifted, *anticipate potential fraud*. The Steam API has functions like `GetUserInfo()` and `GetReport()` that can help monitor this. [See docs for microtransactions.](https://partner.steamgames.com/doc/features/microtransactions#3)|
|Monthly revenue report|Provides a detailed breakdown of sales, refunds, taxes, and net payout. CSV exports.|
### Multi-game release
Once you have more than one game Alden pointed out that you can start comparing them to each other using the top menu of the sales portal, allowing you to see various reports and easily compare all your games in aggregate.
Key areas to consider in multi-game release scenarios are:
|Metric|Description|
|---|---|
|Bundles sales data|Compare the performance of your game in both standalone and bundled formats.|
|Regional sales stats|By comparing how your games perform in different regions, you can identify key geographic areas for marketing and localization.|
Alden recommended checking out the [Steam API documentation](https://partner.steamgames.com/doc/api) for a detailed understanding of the various features and how to use them.

View file

@ -0,0 +1,107 @@
---
title: Actionable Values
description: ''
category: studio-development
tags: []
accessLevel: member
author: Weird Ghosts
publishedAt: '2025-11-10T10:52:42.621Z'
---
# Actionable Values
## Overview
Interested in **developing collectivism within your studio?** You're in the right place!
You know that the studio structures that dominate the industry, and the methods they use to maximize profits, lead to **toxic outcomes**. But we all need money to live. So how do we strive for alternatives?
Of course, there is no single, perfect alternative. But we can support each other as we look for a better way, and challenge each other with the various types of alternatives we're building.
In this article, we're going to take a deep dive into the heart of what makes a collective-minded studio thrive. We explore how foundational values are not just stated, but actively integrated in every facet of our operations. From understanding how our team members relate to our values to examining their practical application in decision-making and daily interactions, we'll discuss how they shape work cultures.
## Common Studio Pain Points
We've seen many common pain points in the Baby Ghosts program, including:
- How do we make more money?
- How do we prioritize?
- How do we scope our game?
- How do we reach our audience?
Everyone needs the answers. But these pain points are a subset of bigger concerns the things that studios often neglect to talk about. The real question is, *why do we work the way we do*? What experiences are informing us? Why are we making what we're making in terms of scope and design? These are studio-wide questions and are part of larger, less frequently addressed problems that stem from fundamental work practices and experiences  and our values.
## Defining Actionable Values
Here is how Gamma Space embodies these values in our processes to navigate various challenges.
First, we see video games as **tools for change**—a concept and *practice* mirroring our values. We prioritize **collective care and well-being**, ranking it high among our top five principles. Emphasizing vertical engagement, we commit to **personal and group accountability**—there's no merit in values without real adherence and engagement. Finally, **empowering individuals** and supporting their personal growth and agency is crucial. We also strive to challenge entrenched industry norms, advocating for equity. While 'equity' is a concise term, it encompasses broader issues we can explore further. By aligning decisions with these values, we can address both immediate challenges and broader concerns, leading to more equitable and sustainable practices.
![gamma space values](/img/gamma-space-values.jpg)
Our values should inform our actions: the why, what, and how. At Gamma Space, we're driven by the belief that video games can instigate change. Our goal is to confront systemic biases. And we plan to achieve this through three main strategies: nurturing collective care, fostering accountability, and enhancing creative empowerment. This approach helps us scrutinize and refine our decisions, aligning them with our values. For example, when contemplating new projects or allocating funds, these values provide a lens through which we assess options. A solid, shared understanding of our values allows us to delve deeper into decision-making, applying concrete principles to a broader range of questions and challenges.
Translating your values into goals is at the heart of [social impact](https://weirdghosts.ca/blog/a-brief-intro-to-making-your-indie-game-studio-impactful). A tool for translating your values into practical, measurable action is the [results flow](https://learn.weirdghosts.ca/impact-tools/results-flow). This diagram shows how your day-to-day activities flow in the short-, medium- and long-term, up to your ultimate goal. Translating your values into actionable goals is _required_ if you're interested in seeking social impact funds, such as from Weird Ghosts, or one of the other social impact funds in Canada.
## Conflict Between Goals and Values
We are really digging deep into values *so that we can make collective decisions*.
The way values are expressed historically in companies is often just lip service. Traditional companies are explicitly beholden to their capitalist framework: typically a top-down structure, infinite growth, infinite profit, and infinite shareholder value in some cases.
And even if they say things like, well, we're a B Corp, and we're interested in the triple bottom line it's still very difficult for these companies to do. "Good for employees," "good for the environment," and "good for shareholders" are all valued equally because they're still trying to grow as much as they can and be as successful as possible. And part of the problem is that it starts to erase the meaning of these ideals.
## Integrating Values in Operations
So how can values become core to your practice and how you engage with your work? One way is to integrate values into your everyday tools and processes to build **a common approach to introduce and practice ideas**. This is important because if not everybody is speaking the same language, this is very difficult. It means that you're not values-aligned, and everyone is interpreting the "right thing" differently. Expect this to happen  there will always be gradations of this. There's no perfect unity here. But there is an idea that you're working towards a shared understanding.
A participant once called this a "codified" process, and that really hits the nail on the head. When you use tools, your values and impact can be quantified and measured over time. It means that if you start making changes and adjustments and course-correcting, this can be transparent to everyone. As opposed to a situation where the "boss" says "Oh, we had this meeting," or "We talked about this over lunch," or "We'll let this slide this time and do this." We can actually make these decisions transparent. And it's good information for when you re-examine your values this is not a thing that just gets set in stone. Your values and processes might actually change and get more refined.
An example of this for Gamma Space is that we recently updated our code of conduct. We did this because we felt the need to re-examine our anti-oppression framework and to think about how we apply anti-oppression to the space. This resulted in some very difficult conversations for some people. But everyone agreed about why we had to do it, so we collaboratively updated the policy.
This example reinforces how we work together, and our concept of care for each other and challenging systemic norms. So this "work product" or process brought us together because even our internal processes and policies are as important as our external-facing work.
## The Layers of Effect
I want to introduce a tool that we use a lot. It's the [Layers of Effect](https://www.designethically.com/layers) (grab our [Miro template](https://miro.com/miroverse/layers-effect-template/)). It was developed by UX designer [Kat Zhou](https://www.katherinemzhou.com/). It can be adapted for use in large-scale and granular decisions. It helps you understand the impact of your choices before you get to work, and it allows you to thoughtfully project intentional and unintentional effects on your audience.
The process starts with a template resembling a bullseye or concentric circles, where the center represents the primary audience or effect, followed by secondary and tertiary effects. The purpose is to assess the impact of initiatives and activities on the audience and affected people.
Here is an example for an accelerator program for underrepresented game studio founders. This illustrates how initial ideas and potential negative outcomes are considered. One effect is that participants learn various skills, but concerns about reporting, privacy, and intellectual property are also acknowledged as secondary effects. The process involves weighing positive impacts, like community support and network connections, against potential negatives, such as privacy concerns or compromised feelings of independence.
![Layers of Effect](/img/layers-of-effect.jpg)
We also have a spot for the desired outcome.
This is a real board we collaborated on about two years ago to start to develop the Baby Ghosts program. Of course, it's evolved a lot since then. This is a map of our good intentions. "Participants are introduced to value flow to help recognize internal efforts," cool, they're going to learn different ways to value themselves! "Participants learn to present to publishers and other funders." That also sounds like a good thing. "Participants develop project scoping, budgeting and presentation skills," another good thing. We couldn't think of any negative things as a primary effect. But if we take a step out to secondary effects, there might be some negative things.
One example we have is that participants will be encouraged to memo about value flow in their reporting. But reporting and sharing may feel at odds with independence. It just doesn't feel right to some people. Of course, we believe there is more value than downside to openness, but in our experience, some people have a lot of trouble with it.
Reporting may also feel at odds with privacy and intellectual property. Some studios might feel, "Oh, I can't share this because it's our trade secret." Or, "We can't share this in the community, I don't trust what's happening here." That might make people feel less inclined to participate. But there's some positive things here: "Participants feel supported by community," "Participants connect with a bigger network." We can start to balance these out and try to evaluate these things after we put these sticky notes in. We have conversations about them through the lens of our values, to say, why might these things be true? And how can we mitigate them? What is our actual way of dealing with these things that will make this a better experience?
Then we zoom out as far as we can to the tertiary. One is "Participants may be overwhelmed by the scope of the process." And this is a thing that happens!
Once you start getting into it, you might realize, "Oh, we've never had these conversations together as a team to this level! Every time we get a little bit deeper, it becomes a bit more overwhelming.So how do we deal with that? And how can we provide tools for our participants to help them with that? Can we provide opportunities for them to break out, take a breather, talk to us, and have studio workshops between these larger cohort sessions?
And this one's a real one: "Participants may feel this process distracts them from creating their game." We hear you, we want you to make your game too! But we also want you to survive and thrive along the way, and be able to enjoy and celebrate the success of the game afterwards and not just immediately flame out. We want you to continue to be a game studio *after launch*!
We've seen dozens of games built and launched through Gamma Space. And they've all been amazing. But sometimes we talk to creators and they say, "I don't know how to talk about my game," and *also*, "I don't want to share anything about my game until I have a publisher and have money." So many things stand in the way of their success because they are trapped in old ways of thinking.
But other things come at the tertiary level: Co-op behaviour models, valuable methods, and the extension of the reach beyond the program for individuals to other aspects of their lives. And that is what we think is a positive possible outcome from this.
## Conclusion
**Embedding actionable values within studio development is not just about stating ideals but about putting them into play in every aspect of our operations.** From the way we interact with each other to the decisions we make and the projects we undertake, our values guide the way.
By committing to these principles, we don't just create a workplace we foster a _collective_ that thrives on mutual respect, inclusivity, and growth.
## Q&A
**Question:** I'm struggling to separate secondary versus tertiary content. How do you decide the levels?
**Answer:** The tertiary levels are *effects* of the secondary level effects so effects of effects! You have to discuss and collectively decide where these effects lie as a studio. What is the full impact? When you take a step back (and perhaps get some feedback), you might learn that your tertiary effects are actually secondary effects or even primary effects.
The important thing is to imagine the outcomes of each activity and then each effect as you work through the circles.
[Miro template: Layers of Effect](https://miro.com/miroverse/layers-effect-template/)
_This content was developed by [Gamma Space](https://gammaspace.ca) for a 2023 Baby Ghosts cohort presentation. We have summarized and adapted it here._

View file

@ -0,0 +1,258 @@
---
title: Business Planning
description: A business plan is a critical document for impact-oriented studios.
category: strategy
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.221Z'
---
# Business planning for impact
Business planning is often neglected by indie video game studios, who are more focused on getting _this_ game out the door than making plans for the next. On top of that, most game studios are not explicitly oriented around social outcomes, so they may be less rigorous in analyzing their long-term goals. A business plan is a critical document for impact-oriented studios because you've set some concrete goals (and if you haven't, start [here](/articles/results-flow)), and need a realistic way to go after them.
With a business plan in hand, the information you share with potential clients, partners, investors, and the public is backed up by values, goals, and social and financial diligence.
We will provide a starting point if you have never created a business plan or have already written one and need to reframe it for your intended social impact.
::alert{type="info"}
**This article assumes your goal is a sustainable, profitable, impact-oriented video game studio.** If that doesn't apply to you, you might not need a business plan right now. Carry on!
::
So let's break down the what, the why, and the how!
## What's a business plan?
In traditional corporations, a business plan is a guide that lays out how the company **intends to make money**. It's both a map for the company's strategy and a way to get investors hyped.
A business plan does something a little different for a social purpose organization (SPO), whether for or non-profit, co-op or hybrid. It's a road map that shows how the organization wants to make a positive change over the next few years. It describes the nuts and bolts of how you will achieve your ultimate outcome and produce social returns on investment ([SROI](https://www.sopact.com/social-return-on-investments-sroi)) in a financially sustainable way.
Your plan should be a **true expression** of what you intend to do. Yes, you may need it for investor pitches and bank meetings, but its real value is as an **internal** tool. And authenticity is key to it being actually useful to you as you work towards your short-, medium-, and long-term goals.
## Why plan?
So why do you need a plan? With it, you can create the tools and reports you need to seek financing and report to your community. As an impact-oriented studio, these are crucial outputs.
Let's recall the foundational elements that will form the basis of your plan. Make sure you're comfortable with the core tools in your social impact kit, including **financial tools**, **[results flow](/articles/results-flow)**, and your **[impact measurement framework](/articles/impact-measurement-framework)**.
These social impact tools feed into your business plan, which you can then draw on for:
::list
- Crafting **pitch/capabilities decks** for investors and partners
- Designing **one-pagers** for media, partners, and clients
- Preparing **funding applications**, including arts/industry grants
- Submitting **loan, debt, and credit applications** to banks
- **Reporting** to boards, members, and stakeholders
::
![doc-flow-diagram](/content/planning/doc-flow-diagram.png)
Building on your results flow to develop your business plan will allow you to show the detailed logic behind how you intend to achieve your target outcomes. This, in turn, aids in decision-making, from daily operations to long-term strategies.
The business plan is a crucial tool for fundraising (targeting impact investors, foundations, government, sponsors, and donors) and may be required by accelerator or incubator programs. And because it summarizes your impact measurement framework (IMF), it's the go-to document for stakeholders looking to gauge your performance.
In addition, your business plan helps you:
- **Evaluate the viability of your ideas.** A well-considered business plan allows you to test and validate your concepts against reality. Is your game resonating with your target audience? Are you able to hire and train developers from a specific community reliably? If your outcomes veer from your planned course, you know you need to change your strategy and how.
- **Highlight your team's strengths.** Your plan showcases your team members' collective expertise, values, and skills. It shows how each person's strengths align with and drive your studio's mission forward.
- **Outline your strategies for both business and social impact.** You can hope you have a hit on your hands, or assume you'll have impact if you're a creator from a marginalized background making a game that represents your experiences. But a plan lays out, step-by-step, exactly how you will _ensure_ your studio is sustainable and impactful.
- **Keep your work aligned with your goals.** With a clear plan in place, you can check in on your progress against your goals. In tandem with your IMF, reviewing and updating your plan means that every decision and action aligns with your studio's ultimate outcome.
## The how
### Planning to plan
We'll repeat it: Before you get to keyboard clacking, complete your [results flow](/articles/results-flow) and [impact measurement framework](/articles/impact-measurement-framework). They are essential resources for your plan. And having them will make certain sections a snap to write!
Another consideration is who should be included in the drafting, editing, and finalization processes.
If you're a small team with little hierarchy (maybe a co-op?), everyone should be included at some point. Do a draft, then pass it to the team for their edits and feedback. Consensus is a must.
The CEO or founder(s) may write the first draft in a larger studio. Engaging the development team, marketing and community managers, board members, legal and compliance folks, financial specialists, or business analysts is still crucial. If you have the budget, it's worth considering hiring external advisors such as impact consultants, diversity and inclusion specialists, or industry experts.
Feeling daunted? We've created a template with section checklists you can use to get started. No one likes staring at a blank page. [Check it out here.](https://docs.google.com/document/d/1AGXb1Z3GrA2dIsYUEsJs-JhCsP2zsQApedZ3p3b31es/edit?usp=sharing)
## The Core Elements
There's no shortage of business plan how-to articles that prescribe more sections or more detail than what we recommend here. Consider this a minimal starting point that covers all you _definitely_ need when approaching social finance investors. At the end, we'll suggest some additional sections you may want to include based on the audience for your plan.
The elements we'll cover here are your mission, team, operations, SWOT, market, money, and measurement.
### Mission
Your mission can be written as a summary of the branches of your results flow, positioned as _what you do_, followed by a restatement of your ultimate outcome (a description of the changed state of the world should you be successful).
::alert{type="info"}
**Reflect:** Does your mission clearly articulate each of your core activities and how they connect to your ultimate outcome?
::
**Example:**
> At Quixelate, we champion LGBTQIA+ narratives through our games, ensuring players not only enjoy diverse characters but also develop empathy and become advocates for inclusion. Beyond the screen, we're cultivating an inclusive community where every member feels seen, heard, and valued. Through our educational initiatives, we aim to share LGBTQIA+ experiences with the wider public, turning passive participants into active allies. Our mission is a world where LGBTQIA+ identities are understood and accepted in games, mirroring a society that celebrates diversity and inclusion.
### Team
**Who do you have on board?**
Describe the experience and skills of each member. Keep the bios short just a sentence or two with a straightforward accounting of their unique capabilities that connect directly to your needs.
**Who (what expertise) is missing?**
Identify any gaps in personnel and how you intend to fill them and whether they are contractors, employees, members (in the case of a co-op), or consultants.
**Describe your collective capabilities.**
Describe your established partnerships, any key technologies or intellectual property (IP) you've developed, and access to special resources such as relationships with platform holders, distributors, and publishers.
::alert{type="info"}
**Reflect:** How does our team's composition reflect our commitment to diversity and inclusion?
::
### Operations
**How will you deliver your games?**
Your business model is your plan for generating revenue. Will you sell games directly to players, rely on in-app purchases, or try a subscription model? Consider post-launch support, updates, and community engagement events that can add longevity to your games and encourage player loyalty.
**Describe how you will fund your projects, team, and mission.**
For an impact-oriented studio, there's a delicate balance to strike between social outcomes and financial objectives. Without financial sustainability, you'll be hard-pressed to achieve your ultimate outcome.
**How does your structure support your model?**
Your studio's legal and organizational structure plays a huge role in how you operate and pursue your social goals. Are you a sole proprietorship, partnership, traditional share corporation, co-op, or non-profit? Learn more in our article [Business Structures for Impact](/articles/business-structure).
::alert{type="info"}
**Reflect:** How have we integrated our social impact goals into our operational strategy? Does our organizational structure support our social impact objectives?
::
### SWOT
A SWOT analysis identifies the **strengths**, **weaknesses**, **opportunities**, and **threats** that apply to your studio.
| **Category** | **Description** | **Examples** |
|----------------|-----------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| **Strengths** | Internal positive attributes of your studio that give you an advantage over others. | Strong brand identity, unique art style, financial security. |
| **Weaknesses** | Internal challenges or shortcomings that may hinder your success. | Tight budget, platform dependency, skill gaps. |
| **Opportunities** | External factors you can capitalize on. | Growing market in a specific region, collaborations, community engagement. |
| **Threats** | External challenges that could negatively impact your studio. | Oversaturated market, economic downturn, changing player tastes. |
**Identify and SWOT comparable studios.**
Select two or three studios whose structure, games, or success reflect your aspirations, and conduct a _light_ SWOT analysis on each of them. Look at Steam pages, web sites, social media, and industry tools like [VG Insights](https://vginsights.com). No need to write paragraphs a succinct point for each category is enough.
**SWOT yourself.**
Conduct an analysis on your own studio. Identify two or three key points for each category.
**Summarize your position amongst your peers.**
What gaps did you identify, and how will you fill them? How do your strengths stack up against your dream studios'? This assessment will provide a clear understanding of your competitive landscape.
### Market
This section, unlike the rest, focuses on your game(s) in-development rather than your studio overall. No matter how important your mission is, it can't overcome a lack of market knowledge and real demand for what you're creating.
**Who will buy your games?**
Get to know your target audience. What are their preferences, needs, and desires?
**What external validation drives your decisions?**
Before launching, test your concept even on a small scale. Conduct beta tests, gather feedback via surveys and interviews, and adjust accordingly. Describe your testing strategy here.
**Include indicators that show demand.**
A thorough market analysis of your currently in-development game will provide insights into the demand for your style, genre, and price point. Look for trends, surveys, or studies that indicate a gap in the market that your studio can fill. (If you're a Weird Ghosts investee, we have an article and template for market analysis on our [Vault site](https://vault.weirdghosts.ca/insights/basic-market-analysis).)
**Articulate what sets your studio apart**.
In 2022, over 12,000 games were released on Steam[^1]. Why should players choose your games? What experiences or narratives do you offer? How do you engage with your community, and why should players return to your games? What is special about your studio?
**Include rationale for your pricing strategy.**
Lastly, your pricing strategy should reflect the value you offer and be sustainable for your studio. It's essential to balance accessibility to your audience and ensuring you're making enough so that you can continue to deliver impact.
::alert{type="info"}
**Reflect:** Does our market analysis consider audiences or segments that align with our social goals? How does our business plan address these segments' unique needs or preferences?
::
> **Example Market Analysis Summary:**<br/>
Quixelate's primary audience consists of players who appreciate narrative-driven experiences with a focus on diversity and inclusion. Our market research indicates a strong demand for such games, with an average sales estimate of approximately 124,751 units per title on Steam alone. The average net revenue from Steam sales for games in our genre and style stands at a promising $1,447,906. This is further validated by the success of titles like "My Time at Portia," which has over 29,000 reviews and an estimated 1 million sales, translating to a net revenue of over $15 million on Steam.
![market analysis](/content/planning/market-analysis.png)
[^1]: [Steam Market Data 2022](https://vginsights.com/steam-market-data)
### Money
**What do you need to start up?**
Every studio needs some capital to kickstart operations and scale. You might be bootstrapping, or benefiting from generous friends and family. Outline what you have, what you need, how you'll allocate the funds, and your repayment strategy.
**Make realistic revenue projections.**
Look to your market analysis to forecast your game's financial performance, and factor in other revenue streams and future games.
**Provide an overview of your expenses/costs.**
This includes production costs, marketing expenses, overhead, and other costs contributing to revenue generation. These apply to your studio as a whole not just your currently in-development game.
**How will you become financially sustainable?**
You do not need to show massive growth if your goal is simply to pay yourself and your collaborators a living wage, that's fine! Outline how you plan to achieve sustainability, ensuring the business remains operational and true to its mission.
**How will your performance be measured?**
Social investors typically want a blend of financial and social returns. Your plan must describe the potential social return on investment and a framework for assessing social performance (detailed in your IMF).
**Attach financial statements.**
If you have already started up, note here that additional financial information is available in the appendix. You may want to include your one-year cash flow, profit and loss, and balance sheet.
::alert{type="info"}
**Reflect:** How are we allocating resources to achieve both financial sustainability and social impact? Does our financial strategy consider potential partnerships or funding sources that align with our social mission?
::
### Measurement
**Provide an overview of social outcomes.**
You have defined your desired outcomes in your results flow, and detailed the indicators you'll use to track progress towards them in your IMF. Provide a succinct overview of them here.
**Describe the role of indicators in tracking progress.**
Your indicators provide tangible data points that can be measured and analyzed over time. Describe the key indicators you've chosen and why they're relevant to your mission and studio business.
**What tools and techniques will you use to gather data?**
This could involve surveys, feedback forms, analytics tools, or even in-game metrics. Also, provide an overview of how often you'll analyze this data, whether monthly, quarterly, or annually.
For a deeper dive into the intricacies of the impact measurement framework and how to effectively implement it in your studio, refer to the [IMF article](/articles/impact-measurement-framework).
::alert{type="info"}
**Reflect:** How does our business plan detail the metrics and methods for measuring social impact? Are there clear milestones and timelines for assessing our social impact progress?
::
### Executive summary
This should be the last thing you write, but the first page of your document. It's a rich, compelling summary of your whole plan. You want to draw the reader in so they want to read the rest of the document. Make sure each section of the plan is succinctly summarized.
### Appendix
Label and attach additional documents, such as financial projections, pitch deck, or other evidence for any of the elements of your plan. Be sure to include a page or section number where any document is referenced in the body of your plan.
### Additional sections
You may consider fleshing out your plan with some of the following sections, depending on your audience:
- Technology and tools used in game development.
- Intellectual property protection.
- Marketing and community engagement strategies.
- Diversity and inclusion initiatives.
- Sustainability efforts.
- Risk mitigation strategies.
- Exit strategies.
## Service-based business
Tweak your lens if you're a studio focused on service work or clients. Anchor around a key technology or approach, seek clients who can access social finance, or partner directly with an investor and operate as an agency that supports social-purpose organizations. Treat yourself as a client and prove your model with a prototype to generate evidence for your IMF.
## A cooperative approach
**Experiment with the format.**
It doesn't have to be a dry Google doc! We know some folks love Notion, and other tools like Canva and Miro can help you visually lay out your plan. Keep in mind who you aim to share it with and make sure the format is accessible and readable for them.
## Reward and make collaboration frictionless
It's not just for the bosses. Consider how easy it is for your team to access and make changes to it. Invite regular feedback and updates and make it a pleasant experience. We use shared a shared vault in Obsidian, and track Markdown files through Git.
**Build review cycles into your internal schedule and processes.**
It's only useful if you use it, and that means updating, changing, and adding as you learn what is working and not with your studio. We recommend reviewing your plan every three months, and updating your Measure section with data from your IMF.
**Consider radical transparency.**
Make it public. Publish it and show how it has changed over time. Allow others to clone or fork it on Github!
## Finally…
The most important question we'll leave you with is: **What do you hope to get from your business plan?** Your answer will lead the way if (when!) you get lost in the details. This process is, first and foremost, for *you* and the impactful studio you are building. We'd love to see your plan! If you want to share it with us, email us at [hello@weirdghosts.ca](mailto:hello@weirdghosts.ca).

View file

@ -0,0 +1,77 @@
---
title: Canada Council Funding
description: ''
category: strategy
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.229Z'
---
# Fund your game with Canada Council
Notes based on 2022 webinar with program officer Megan Leduc, who has been working with Canada Council 10 years with Explore and Create team.
- CC gets back to people with questions within 3 days.
- Must create an account in the portal first.
- Log in or check eligibility.
- Pick the type of artist you are - Individual or Group/Organization.
- Pick artistic practice - Digital Arts or Media Arts (can select both).
- New and Early Career profile also available.
- Self-identify: Priority groups.
- Indigenous (also Creating Knowing and Sharing program).
- BIPOC.
- Language minority.
- Deaf/disabled.
- Submit CV to verify experience.
- Once approved, all grants youre eligible for appear in the portal.
- Games are art, according to Canada Council.
- Tech-based art has been funded for 40 years.
- Upcoming cutoff date - October 5, results end of February.
- Can apply after but results will be later.
## Research and Creation
- Early phases of your project - everything up to prototyping.
- Test out new tech, tinker, research.
- Up to $25,000 per year, up to 2 years.
## Concept to Realization
- Usually up to $60,000 (exceptional projects go to $100,000).
- Peer assessors are artists across disciplines from across the country.
- High level tech needs contextualization as assessors are probably unfamiliar with games.
What they support:
- Looking for independent artist-driven projects - you are the lead and own the rights.
- Artistic projects with an artistic vision.
- Creators, directors but not production companies.
- Do not support commercial projects.
- Check with Council before submitting to clarify eligibility.
## Top Tips
1. Read the entire application ahead of time. Dont be repetitive and include everything in your first question.
2. Read the assessment/scoring criteria ahead of time (on each program page) and focus on:
1. Impact (contribute to artistic development, advance artistic practice, knowledge of practice - different for different programs).
2. Artistic merit (samples, rationale, outcomes).
3. Feasibility (capacity and experience to undertake project - history of previous work, samples, reasonable budget, including other revenue and ability to provide reasonable working conditions).
3. Be authentic, ensure you have a hook.
4. Be clear and concise - dont be too in your head. Get another person to look at your application.
5. Be consistent throughout your application.
6. Support materials:
1. Show your experience and ability to carry out your project.
2. Assessors will only spend 10 minutes with this. Put important stuff at the top.
3. Include samples, drafts, storyboards for the project.
- Criteria is used to rank all applications and as many projects are funded as there is budget.
- Recommended projects sometimes get redistributed funds throughout the year.
- Priority groups are sometimes pulled from below the success criteria line to be funded.
- Disability - honour system, self-identified.
- Barriers - contact them 2-3 weeks before deadline for assistance.
- Access support - grant that covers costs incurred while applying (can be applied for after the fact).
Eligibility: It all comes down to artistic project (fundable) vs. commercial product (not fundable).
- A T4A slip is issued at the end of the year. It is not a gift but taxable income.
- Council is not a producer and takes no rights to your project.

View file

@ -0,0 +1,91 @@
---
title: CMF Quick Tips
description: ''
category: strategy
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.229Z'
---
# CMF Application Tips & Info
_With help from [Astrid Rosemarin](https://twitter.com/astridrosemarin) and Tamara Dawit!_
## Background
- The Canada Media Fund (CMF) has its roots in Telefilm, which was established in the 1960s. Over the years, it has evolved to support a broader range of media.
- CMF is run and administered by Telefilm, which means it operates within the framework and guidelines set by Telefilm.
- The language used in film production is different from game development. E.g., in the film industry, "production fund" refers to the active creation of the project, while "development" refers to pre-production activities.
- Banks are typically reluctant to provide bridge financing for games. This type of financing is used to cover expenses before the release of the game, which can be risky for banks.
- The definition of "done" varies between film/TV and games. This can lead to confusion and miscommunication when dealing with funding and project completion.
- The CMF is aware of these issues and is actively working to improve its processes and guidelines.
## Experimental programs
- Convergent programs are designed for broadcast TV.
- Experimental programs cater to Interactive Digital Media (IDM) and software projects.
## Budget cap
- CMF can fund up to 75% of a project's budget.
- The maximum funding amount is $1.5 million across all programs.
## Fiscal Year
- The fiscal year starts on April 1 and ends on March 31. This is when new budgets, deadlines, and guidelines are refreshed.
## Programs
1. Accelerator partnership: A program designed to foster partnerships and collaborations.
2. Commercial projects program: This program focuses on projects with strong commercial potential.
3. Conceptualization: This is a first-come, first-served program that provides up to $15k for testing a proof of concept.
4. Prototyping: A selective program aimed at building a functional prototype for testing and validating concepts.
5. Innovation and Experimentation: A highly competitive program with a long lead time, aimed at funding IDM projects that push the boundaries of innovation.
### Conceptualization
- This program is first-come, first-served and provides up to $15k for testing a proof of concept.
- It serves as an entry point for future rounds of funding.
### Prototyping
- This program is selective and not first-come, first-served.
- It's designed to help build a functional prototype for testing and validating concepts.
- There are spring and fall deadlines, and the budget is split between these two periods.
### Innovation and Experimentation
- This program is very competitive and requires a long lead time.
- It's designed to fund IDM projects that are innovative and push the boundaries of what's possible in the field.
### Commercial Projects Program
- This program is similar to the Innovation program but has a stronger focus on commercial viability.
## Tips
1. Read the guidelines carefully and repeatedly, especially for selective/scoring matrix programs.
2. Weight your application according to the scoring grid, spending the most time and effort on highly scored sections.
3. Set up your online account well in advance.
4. Understand the importance of diversity and gender considerations in your application.
5. Work systematically against the list of required documents.
6. Talk to other developers who have successfully navigated the process before.
7. Allow plenty of buffer time to compile the necessary documentation.
8. Ensure your budget aligns with the CMF framework.
9. The core of your application should be your innovation.
::alert{type="success"}
Remember, the CMF does not cover 100% of the budget - it's intended to provide support, not full funding.
::
## Changes to guidelines (2022)
The overall budget for the Canada Media Fund (CMF) remains the same as in previous years, and the flexibility measures introduced in response to the pandemic will continue.
### Equity, Diversity, and Inclusion (EDI) Programs
- EDI programs, which were launched in 2021, will be expanded this year.
- The definition of diverse communities now includes 2SLGBTQIA+ individuals and persons with disabilities, in addition to Indigenous and racialized communities. The definition can be found in section 2.1.1 of the program guidelines and in appendix A.
- The term "gender balance" now includes "individuals that identify as women".
- Only paid positions are considered when assessing diversity and inclusion.
- The CMF is introducing a new Accessibility Support initiative to assist individuals who face barriers to completing the CMF application process.
- The CMF is formally launching PERSONA-ID, a new self-identification system designed to measure and monitor the demographic representation and participation of all individuals with ownership and control on projects seeking CMF funding. This system is required to earn points for EDI, but is otherwise voluntary.
### Experimental Stream
- The CMF is encouraging applicants to implement more environmentally sustainable practices. This may become a requirement in the future.
- Previously, applicants who had received any funding from an interactive Experimental Stream Program were excluded from applying to the Program. Now, the exclusion only applies to applicants who have received previous production funding from an interactive Experimental Stream Program. Applicants who have previously received funding from the Conceptualization and/or Prototyping Programs are now eligible to apply.
- At least 25% of the Conceptualization Program's budget will be exclusively reserved for projects where at least 40% of the enumerated eligible positions are held by members of diverse communities.
- The insurance requirements have been updated.
- There have been changes in the reporting requirements for digital media.
### Convergent Stream
- Nothing relevant.

View file

@ -0,0 +1,138 @@
---
title: Co-op Structure
description: ''
category: studio-development
tags: []
accessLevel: member
author: Weird Ghosts
publishedAt: '2025-11-10T10:52:42.623Z'
---
# Co-op Structure and Value Flow
Welcome to an exploration of the cooperative structure in game studio development, a model that redefines the traditional workspace by prioritizing _collective ownership_ and _shared decision-making_.
In this article, we will look at the unique facets of a co-op setup, examining its foundational principles, operational dynamics, and its inherent benefits and challenges. We'll also discuss how this structure aligns with values like inclusivity, democracy, and sustainability and explore practical aspects such as legal frameworks and governance models.
## Co-op Basics
- Read more: [Structures to Consider: Coop](/studio-development/structure/structures-to-consider/coop)
Let's start by talking about co-op basics. Co-ops are a unique business model distinct from other business corporations. They can produce products or offer services that can be for-profit or not-for-profit. They're not attractive for investment by default but _can_ be structured for preferred shares in for-profit co-ops. This is a lesser-known setup that we'll get into later.
Let's look at four ways co-ops differ from corporations.
### Ownership and Voting
One is ownership. Shares that are issued to owners don't change in value and can't be transferred. They're independent of value, regardless of what happens to the co-op. However, members can exit and sell their shares back to the co-op. This varies from province to province a little bit, but generally, there is a minimum of three directors required legally by the CRA (or Revenu Québec).
Voting: one member, one vote regardless of shares. This is important and a huge difference from typical corporations. Some of you may have indulged in *Succession* over the years and know shareholders have a lot of power based on how many shares they have. But in a co-op, one member gets one vote regardless of the number of shares they hold. Profit is distributed to members based on shares after expenses, reserve funds and other goals that can be set by the co-op.
### Structural Overview of Co-ops
A typical structure for a co-op has members at the top. The members elect *directors*, and the directors hire *management*. Management generally hires or pays workers who are members (or they could be contractors). When the workers are the members, that is a worker co-op. That is how worker co-ops work from a purely legal perspective.
If you're a consumer or producer co-op, your members make a product or provide a service. You've probably seen grocery co-ops or farm co-ops. In Alberta, you might be familiar with farm equipment co-ops as well. In any case, ultimately, the members benefit.
### Collective Mindset
It's important to remember that *collectivism* is at the heart of what we've been talking about so far. Co-ops support collectivism in a unique way, where every member is entitled to one vote regardless of their shares. Legally required governance enforces the development of shared values, as we have discussed previously. Shared values, in turn, encourage consensus-based goal setting, which cultivates a collective mindset. Collective goals lead to *resource sharing*, creating a cycle of mutual support. This interdependence is precisely why co-ops are ideal for collective thinking and developing collaborative processes.
## Co-op Legal Structure and Registration
If you haven't registered your co-op yet, here are some things you want to know. There are boilerplate bylaws available, but they don't say much about what members get or the expectations of shares or value. You have to go beyond that. If you go to a legal service or a lawyer to register your co-op, they will probably give you these boilerplate bylaws. Even if you go through a paid program, like Ownr, you might not get information on how to read them. There are differences between federal and provincial registration, affecting how you do business and the services you offer.
## Gamma Space's Node-Based Model
So, let's talk about how Gamma Space fits into something like this because it's a subject we can talk about. We're in it, we're operating it. Gamma Space is a node-based not-for-profit. It is driven by our values framework. Members develop studio relationships with each other, and we ensure value flows to everyone participating. And we're working towards a regenerative ecosystem of those flows.
![](/img/co-op-structure.jpg)
We are different from other studios because we have been involved with both members and non-members for over 10 years. Non-members are not part of our cooperative but are actively involved with us through Slack and other ways. We have not cut them off, and although they do not receive the same benefits as members, they still contribute to the community. Some non-members have even ended up working with members or collaborating with us.
## Value
Let's talk about value. People often bring up practical considerations like not working for free and not asking others to work for free. These ideas are well understood, and we fully support them. It would be unethical and antithetical to our mission to do otherwise. We need to be transparent about what we're building at all times. 
For some co-operatives, members need to make a buy-in, which can be financial or some other agreed-upon commitment. For example, at one point, Mountain Equipment Co-Op required members to pay a yearly fee, which helped them build up the capital to fund their operations. There are also grocery and farming co-operatives that require a buy-in. 
In a worker co-operative, members may need to contribute a certain amount of money or time to earn ownership shares. Credit unions are an excellent example of this. The important thing is that everyone understands what their ownership entails, whether it's through a financial investment or sweat equity. 
Shares in a co-operative don't increase voting power, but they can be traded or valued in some way to honour an agreement. For-profit co-operatives can also bring in non-voting investors who get preferred rights to extract value from the co-operative. These investors don't have any say in how the co-operative is run, but they get the first cut of profits. 
It's up to the co-operative to decide the value of these shares and how important it is to have operating money on hand. If a member leaves and wants to cash out their shares, the value must be filtered through the investors first. Ultimately, the co-operative values and priorities should guide all decisions.
When a member decides to leave, they can withdraw the value they have put in, which is based on the number of shares they hold. But if your co-operative has a complicated share structure, and a member decides to exit, it can create a difficult situation. You should discuss what happens if the co-op doesn't have enough money to pay the exiting member or what the exiting member is entitled to. This is particularly important to consider for worker-owned co-ops. While this may not be immediately obvious for game studios, it is more evident in brick-and-mortar businesses where there is a tangible product or service.
## Accommodations and Accessibility
This is a conversation that is constantly happening. It allows for experimentation. But most of all, it allows for the _broadest range of participation_ and capacities. Some might ask, "What about accessibility?" What about people who do one thing really well, learn at different speeds, or have different learning needs? If you have this granularity, it can be accommodated from the ground up instead of waiting until you get the money. 
And because it's so granular, it can be assigned to any type of work, including member-created games. The way our studio works is that every member is working on a game. It's one of the conditions for membership: A game project. It can be very slow, it doesn't have to be your masterwork game  but you are developing a game to participate in your own personal development and potentially work with others.
And that's why we have value flow.
## Value Flow in the Studio
We characterize value in our work in four ways. The first is **livelihood** work, which is the work we do for money that is client-facing or deliverable-based. We represent this value internally with the 🌽 (corn) emoji. The second way is **intentional** work, symbolized by the 🎯 (target) emoji, which involves direct participation and support we offer to another member because we feel the same level of support from them. This is like a sophisticated bartering system where we can intentionally record, denote and share an exchange of value that isn't actually transactional. It's based on mutual respect and trust, where we agree to help each other out without any expectation of immediate return. 
The third way we value our work is through **community** work. This is the work that glues us together, and is often (otherwise) invisible. It's about social cohesion and collective benefit. For example, someone has to make sure to remember to do the filing for x, or someone has to post that social media reminder, even if there isn't a role yet. We track this type of work, which is often overlooked but essential for the community to function smoothly, with the 🚰 (potable water) emoji.
![](/img/gamma-space-value-flow.jpg)
All three of these values are transmutable and negotiable. It takes time and space to work these things out, but aligning with our values is important to have a grounded community. This is why we are so focused on values.
**Personal** or self-work (symbolized by the 🌀 cyclone emoji) is the final flow we consider, with an understanding that personal growth and development ultimately benefit the community. It should be an integral part of our values. It can't be just an occasional thing that happens on professional development days or when there is enough money to spare. We need to make room for it and structure it reasonably with our ultimate goals at the top of our minds. Everyone has their own version of this, including spending time learning Godot or a new feature in Unreal or something like that. Personal investment ends up percolating up to the rest of the community. And we track it, but it doesn't necessarily get transmittable in the same ways as literally as the other three.
These are absolutely not prescriptive ideas, by the way. This is how _we_ are experimenting with collectivism and meant to be an example. If you're on the journey to creating a collectivist studio, you are already helping shape new ideas and concepts. You might use these ideas differently than we do, but hopefully, they get your brain going about the possibilities and why we're so focused on values.
## Co-op Structure and Value Flow
Going back to what we learned about the accelerator earlier, we can now add attributes to it. For instance, the role of being the lead is high intensity, and requires high availability and a strong commitment to stewardship. This means that you'll need to have access to 🌽 livelihood funds flowing in and out for community development purposes.
![](/img/gamma-space-value-flow-example.jpg)
### Accelerator Node: High-Intensity Roles and Responsibilities
Now that we have established the high-intensity, high-availability, and stewardship commitment, we can discuss the specific responsibilities that come with it. These responsibilities include program coordination, impact measurement, funder presentations, and other detailed tasks. By breaking down these tasks, we can delegate them appropriately and even split larger roles when necessary. We can also identify any ad hoc work that needs to be done and allocate it to members who have the necessary skills. For instance, if a member is close to finishing their own project, we can offer them some extra pay to complete smaller tasks. We have the necessary tools and processes in place to make this happen.
## Mapping and Visualizing Co-op Nodes
When we examine our co-op nodes, we can begin by placing things where the ins and outs are. We can contemplate the idea that publishing is _in_ livelihood (it's actually _out_ livelihood as well), as it supports the community as a whole. We can start mapping and visualizing what this looks like in detail. This process helps us model our studio and bring clarity to our work.
It may take a while to get here it's a cumulative process. And it requires patience.
## Value Accounting
Let's talk about how we discuss _value accounting_. We need to do this at every level of our nodes, with our various projects and commitments with each other. We look at the value flow assignments we have tracked and discuss them in detail. The conversation is based on our recorded information, but the anecdotes are equally important.
For instance, when someone spends a lot of time on a task, and it takes an emotional toll on them, we should consider that in our value accounting. This emotional hit can impact their ability to work on other tasks, and we need to be flexible to support them. We should make room in our budget to support members who do this work, even if it means working an extra day. It is not something that should be expected of them all the time.
### Addressing Workload Challenges
[At the budget accounting meeting], you might think, "We don't have the budget to [pay for] this [task we've asked one person to do]!" One person is doing a hard task, and nobody else can or wants to do it. The person is now asking for livelihood flow because the task took away time from other important things. The team is asking them to do it again next week, but the person is feeling the strain. They ask, "Can someone else take this on for next week, knowing that it's affecting me [adversely]? I can provide you with all the information you need, but I need a break from actually doing it." In this way, you can transform this from a burden on one person to a collective support effort. By sharing the workload, you can ensure that no one person is overburdened.
### Technology
Some co-ops (e.g., [DisCo](https://www.disco.coop/)) use blockchain and DAOs to track work, but we reject that approach. It is critical to prioritize _human conversation_ and measure it against your values. This allows you to practice and understand power dynamics. We cannot rely on computers to make these decisions for us. The decision-making process has to come from conversation.
This process may feel incredibly slow. We're developing an entire business model around it, and collaborating with many people with unique perspectives. Distributing resources fairly is essential, and we have clear ideas about the attributes that matter. We haven't discussed these attributes in detail yet, but we will later.
## Role Differentiation and Team Development
Under our roles, we have categories for intensity and expectations. For example, we differentiate between stewardship and simply completing a task. We need to clarify the requirements for each role and determine if we have the necessary expertise. If not, can we train our team members to fill those gaps? We need to weigh the pros and cons of investing time into training versus immediate productivity.
### Prioritizing Fair Wages and Sustainable Business Models
We have experimented with various business models, including contract game development services and web development. However, we now prioritize a model that provides immediate income with fair wages for the most number of people. Although it may be more challenging to implement, it allows our team members to invest in their own projects and secure production funding for their work within a shorter time frame.
## Conclusion
Coops represent a transformative approach to collective work and creativity. By embracing a model grounded in shared ownership, democratic governance, and mutual support, we pave the way for a more inclusive and sustainable video game industry. This article has illuminated the key aspects of implementing and sustaining a co-op structure, highlighting both its potential to empower and the challenges it may present. Next, we will look at decisions, conflict, and prioritization
## Questions to Consider
- How is value communicated and tracked within your co-op?
- How do your values inform roles and skill development?
- Is investment important to you?
_This content was developed by [Gamma Space](https://gammaspace.ca) for a 2023 Baby Ghosts cohort presentation. We have summarized and adapted it here._

View file

@ -0,0 +1,287 @@
---
title: Decisions and Conflict
description: ''
category: studio-development
tags: []
accessLevel: member
author: Weird Ghosts
publishedAt: '2025-11-10T10:52:42.624Z'
---
# Decisions, Conflict, and Prioritization
## Overview
In this exploration of decision-making within a collective studio environment, we navigate the intricate dynamics of _collective consensus_ and _collaborative governance_. This article delves into the methodologies and practices that make decision-making in a co-op structure both unique and effective. We will explore how to balance individual voices with collective goals, the importance of transparent communication, and the tools and techniques that facilitate democratic decision-making.
## What Are Decisions?
So, decision-making! Decisions, decisions, decisions. What exactly are decisions? And why do we decide?
We make decisions to come to a resolution or agreement as a result of consideration. Sometimes, it can be straightforward and swift, and sometimes, it can be really frustrating or even vague and nebulous. So, what do we do? We try to figure out the alternatives and options. We try to gather the information or knowledge that we need to make informed decisions.
When situations, opportunities, blocks, or barriers arise, decisions are important because we need to make a judgment. That judgment will help us to act with as much information and consideration as possible. Sometimes, it's a worst-case scenario, but sometimes, it's a breakthrough scenario, where decisions help us to resolve or settle a question or a contest. Sometimes, when something comes up, people have wildly divergent opinions, assessments, or analyses of what's going on. The decisions will help break a block, stalemate, or place where we feel at odds with what is happening.
It's worth breaking it out like this because decisions are so present in our everyday  from the time we get up in the morning, to the food we eat, to whether we go to work or not. Do I want to go back to this horrible job? Or do I want to be broke? There are big decisions and small ones thousands that we all make each day.
There are some truisms about decisions. Because there are a lot of very learned people and people who have gone deep into what it means to make decisions and how they run our lives, and just how all-encompassing our decisions are.
Many people have experienced writer's block or creative block and have procrastinated. People who have a brain difference or have lived through periods of trauma may find decision-making challenging. When faced with these situations, it can be painful, and sometimes it feels impossible to make a decision. We start to realize that we are our decisions.
### Context
Many Indigenous cultures around the world believe that the decisions we make today will affect our descendants for seven generations. This concept applies to things like the environment and how we use our resources. Every decision we make defines who we are, and we often don't realize it.
Nelson Mandela said, "May your choices reflect your hopes, not your fears." There are a lot of fear-based decisions that dominate the world and lead to more fear-based decisions that lead to violence, conflict, war, and a lot of harm. It's worth keeping as a guiding light the idea of making hope-based decisions.
Finally, Roy Disney, Walt Disney's younger brother, said, "Decision making is easy when your values are clear." Even at this kind of corporate mainstream level, it's possible to constantly foreground values.
## Approaches to Decision-Making
### Majority Voting
In parliamentary democracies like Canada and confederacies like the United States, majority voting is usually the norm. However, what many people don't know is that there are two types of voting passive and active. While the former is more common, the latter is more transparent and can be very helpful in documenting one's consistency and track record of voting, especially in community organizations.
While majority voting requires at least 50% plus one vote, there's also the concept of a two-thirds majority vote, which indicates a much higher level of support. This is common in places like share corporations and can be essential for ensuring transparency, which is a value that many people prioritize.
**Types of Majority Voting**
| Type | Voting |
| ---- | ----- |
| majority | 50% +1 |
| two-thirds majority | 66% |
| passive | only counted if close |
| active | all votes named and documented |
### Consensus/Unanimous Voting
Aside from majority voting and two-thirds majority voting, there is also consensus voting, which involves reaching an agreement through discussion and compromise. This approach can be helpful in situations where there are multiple stakeholders with different perspectives and interests.
Please note that a unanimous vote may not necessarily be the most powerful indication of agreement. Consensus is more meaningful as it shows the level of intention and engagement of everyone involved in the decision-making process. When everyone is in agreement and actively participates in the conversation, it is a clear demonstration of consensus.
### Passive Consensus
In contrast, there are instances where decisions are made passively, without anyone actively opposing them. For example, in meetings, a topic may be discussed, and without anyone raising any objections or wanting to discuss it further, the group moves on to the next topic. This is also a form of consensus, but one that happens due to a lack of opposition.
It's essential to recognize these moments of passive agreement and understand that they are also decisions being made. You might feel uncomfortable or unhappy about the outcome of such passive agreements. It's crucial to voice your opinion and ensure that everyone is actively participating in the decision-making process.
| Type | Description |
| ---- | ----- |
| Consensus | all present are in agreement |
| Passive consensus | all are assumed to agree unless stated otherwise |
| Active consensus | each person states and documents their agreement |
In a cooperative setting, transparency is essential. Consensus is a great way to achieve transparency, and it is worth considering in the early stages of building a co-op structure, relationships within the co-op, values and alignment.
Where do we make these decisions? And what scope do they have? Structural decisions, such as those that relate to bylaws and legal registration, need to be formalized and made by the whole co-op. However, operational decisions need to be made regularly and collectively. It is important to determine who makes these decisions and how they will be communicated to the group. Is decision-making in the hands of certain people? Is it in the hands of those individuals and not shared between other members? Or are these process decisions being made on a regular basis, and then everyone goes and executes according to collective decisions? It's a question.
Decisions make collaborations work or not work. Decisions can be made based on information and reflection. And they can also be made transparent by narrating them, documenting them and having them made in advance through conversation and dialogue.
Finally, decisions are made not just at the beginning of the flow but all the way through all the stages of your work. They are going to affect your output, whatever it is e.g., we chose to hire somebody, we are bringing more members in, we have applied for grants, we are seeking funding, we are developing a game, and we've now launched and finished the game. Everything that we have as an output is affected.
Let's recap the typical location and scope of decisions:
Members are responsible for decisions that affect the co-op as a whole, so they are co-op-affecting. (If this is not done by members, we're doing something wrong!)
Directors are process-affecting. They might hire based on the decisions of the members (this can be written into the bylaws in very specific ways).
Management is collaboration-affecting, e.g., how you run a meeting.
Workers make decisions around output-affecting things.
![](/img/co-op-structure-2.jpg)
### Node-Based Decision-Making
Gamma Space has a complex node structure that can be confusing to navigate. Let's take a closer look at the flattened node view we discussed earlier. It's a series of expanding circles with nodes attached to them. Although members are still responsible for making cooperative decisions, those decisions are passed up through the node structure to the directors, who help inform the decision-making process.
When we enter a node, we can see that it's responsible for three things: coordinating the process, facilitating collaboration, and delivering the final output. These three responsibilities are always in service to what the members have said they want to achieve. Inside the node, there is a lead member, a support role, and ad hoc participation by other members or contractors. This structure is decided at the node level and passed through to the rest of the team.
If we dig deeper, our community functions are essential to how the cooperative operates, and members participate in these functions based on their respective responsibilities. For example, if we have a governance working group, the directors don't make decisions on collaboration independently. Instead, they collaborate with the group members to make decisions based on a menu of processes available in our operations manual or develop something new. Members still play a significant role in the process.
So, when we talk about the collaboration method, it's still the members who contribute to the output. Each member has a self-contained node, and these nodes have microcosms of all the essential functions. We keep iterating through these different layers and circulating them around, trying to come up with different orders that make sense. We document our progress as we go along.
![](/img/node-based.jpg)
## Values-Based Decision-Making
We have now explored the concept of decision-making, its scope, and its areas. But what about decision-making based on values? When our values are evident, decision-making becomes easy. Understanding the reasons behind it can be helpful.
Values provide direction, motivation, and grounding. When we articulate who we are as a studio, why we collaborate, and what we aim to create, making decisions in all directions becomes more comfortable. Even on groggy Monday mornings, when we wake up feeling overwhelmed by the stresses of the week before, our values help us navigate the day better. When our values are clear, we know what to expect, and we can face the day with a sense of purpose.
Values also help us clarify who is going to be impacted by decision-making? Who needs to be included in any given set of decision-making? And who are we seeking to empower through those decisions?
There's an expression that came out of disabled people's organizing in South Africa: "Nothing about us, without us, is for us." This expression has been applied in many different ways since it came forward in the 1980s. Who is going to actually make the decisions? How are we going to empower those people? Think about how your values inform that.
What is values-based decision-making? What values? Values help determine the needs that we have for our studio and for our individual members making games. They help us with the Layers of Effect exercise, which we will come back to later. What do our decisions determine in terms of our needs, goals, activities, and the resourcing and capacity that we have?
How do we do it? It's a process that will help us define:
- **WHY**: provides direction, motivation, and grounding
- **WHO**: clarifies who is impacted, included, and empowered
- **WHAT**: determines needs, goals, activities, resources, and capacity
- **HOW**: describes the process to inform, discuss, choose, prioritize, distribute responsibilities, document, execute, and measure our work
For the people who make the decisions, that's a lot of responsibility and accountability. And it's a lot of power in the micro and in the macro.
Document decisions. Documents serve as a guide and a reference point for how we execute our work. When we establish a structured decision-making process and consistently practice it, we can anticipate and measure the impact of our work. We can make better decisions and have a clear understanding of our work before we execute it.
Applying our values helps us to prioritize our needs based on what matters most to us. By doing so, we gain a better understanding of the environment we're working in, including the resources we have available, such as people, talent, time, and cash flow.
Our values also determine how we schedule our priorities and allocate responsibilities among team members. Depending on their experience, skills and training, some members may bear more responsibility than others for certain decisions. This helps us to determine the level of commitment and intensity required for each activity.
Lastly, our values guide us in making and documenting our decisions, ensuring that they align with our principles and beliefs.
## Tool Examples
### Collaborative Meeting Format
Gamma Space has developed a set of tools that align with our values and meet our needs. These tools are centred around the concept of meetings and how to conduct them effectively. It involves understanding our resources and power dynamics and creating meeting formats that can be adapted for various situations. The ability to have different people lead and take on different roles in these meetings is a powerful tool.
It's important to think about the outcomes of these meetings and learn from the process. By using visual collaboration methods, this learning process can be sped up.
One of the first things to think about is roles. If one person is always the facilitator, they may be seen as a de facto spokesperson or leader. This is why we rotate that role between members, giving everyone the opportunity to learn new skills. It's important to try to rotate in folks who find it uncomfortable  not to punish them, but to align your practices with your structure and values. (Of course, make space for illness, anxiety, and other accessibility considerations and don't force a role on someone who really doesn't want to do it.)
Give everyone an equal opportunity to contribute when starting out. This covers various responsibilities, such as collecting agenda items if you're the facilitator and ensuring that there is a designated speaker and a rough estimate of how long they will speak. This creates an opportunity for the timekeeper to guarantee a smooth flow of proceedings and ensure that we stay within time at various stages of the meeting. Lastly, there is the secretary role, which involves writing minutes and sometimes creating visual aids.
These will vary by the type of meeting and how you decide to record things. But it's important to designate someone to document or be responsible for the final outputs of a meeting.
First, the agenda. We often make agenda items as visual objects that can be moved and dragged around our Miro board. We describe:
- the duration of each topic in minutes
- who is bringing that item forward
- value flow by emoji (that is, is it related to livelihood, community, intention, or self?)
Right off the top, we have check-in usually just a simple question that can be answered in a few words, like, what's your temperature/weather/vibe today. We then take a moment to confirm the agenda and revise it with any last-minute additions or removals. We make sure that everyone is represented on the Miro board by a different coloured sticky.
Next, each person who is bringing a topic forward identifies the relevant value flow emoji and places it on a Cartesian plane. You can see there is a continuum between different value flow types, such as between self and community; and between livelihood (which is really about resources, either for an individual or for the co-op, depending on the scope of the meeting) and intentional work or something that might be traded in kind.
![](/img/cartesian-mapping.jpg)
During the meeting, we move these emojis around the board. Sometimes, we take a snapshot of our value flow map before and after the meeting to see how perspectives changed.
Each of those items can have sticky notes with more details, as well. This way, we can see how the dynamic of the conversation progressed, which then leads us to extract action items.
The secretary carefully records decisions and action items, such as:
- Update a document
- Buy the software we're talking about
- Draft and send an email
For each action item, we can identify which value flow it relates to.
This is just one example of how decision-making can work. No matter what structure or process you choose, it's helpful to think about:
- Where are you spending your time in a given meeting type or area of your co-op's development?
- If you're spending all your time talking about one topic, is that having a detrimental effect?
- What areas have been neglected in the last few meetings?
- What tools can you use to ensure neglected areas are addressed more frequently?
## Using Layers of Effect
You might be wondering why we're bringing back the Layers of Effect. Haven't we already talked about it? We did, but now you might have more context, and it might make more sense. This tool aids decision-making, helping us understand how our intended impacts contribute to our goals.
We've mocked up what it would be like to discuss switching to Godot, for example. Now we can see what that decision would mean for our studio. Is it important for us to prioritize open-source tools? When we make a decision like that, and it's beneficial, we can measure the impact and make a decision. We can visualize it and decide.
![](/img/loe-2.jpg)
You can mix and match these different tools and components to meet your needs. You will learn what works for you and your team. These are just examples; you might have other ones that work better for you. We always encourage folks to develop their own processes because they'll be more likely to fit your unique values and represent you as individuals in the studio. All of these tools are hackable! Here's the Layers of Effect template.
### Data-Informed Decision-Making
One way to make decisions that are auditable and data-informed is to use some sort of measurement framework. In our example, we're using an impact measurement framework (IMF). Developing an IMF is recommended if you are aiming to have a social impact in your studio. [You can learn more about this topic here.](/impact-tools/imf)
![](/img/imf.png)
One thing we measure is the number of active participants in Slack over time. Assuming we recorded an increase in active participation over a quarter, we would make certain decisions based on that, as increased activity implies greater engagement. It also might tell us about specific topics or times that people are more interested in or active in. Given this interest, we would increase our investment in resources in community-building. We could bring more folks into the community if we see exceptional active engagement. This is one way that we can use data to directly inform decisions in a way that's responsive to the life of your community or your project.
## Values-Informed Tools
When selecting or designing decision-making tools, allow yourself to be guided by the underlying principles of your cooperative. This may seem obvious, but it's worth repeating. Incorporate your values to ensure equitable outcomes, and make sure they are easily referenced, tracked, and summarized. Even if transparency is not one of your core values, it should be a part of your key processes. You could use a value slot to express that you value transparency, but it might be more helpful to articulate how your studio is trying to achieve transparency in a specific way.
## Conflict Resolution
Sometimes, when decisions get made without transparency because people are just rolling with things, conflict can arise. To balance out this topic today, let's look at conflict and conflict resolution.
Reaching a consensus decision or even a majority decision is a collaborative process that involves coming to an agreement through different means. However, conflict is the opposite of this. It is a serious disagreement that cannot be resolved smoothly through normal means. Conflict can become protracted, frustrating, and debilitating to progress in work. It can also cause hurt, pain, or stress that makes it difficult to go to work. Essentially, conflict arises when a person experiences a clash of opposing wishes or needs.
We have discussed the importance of considering needs in addition to goals and aligning them with factors such as capacity. Conflict may arise when there is an incompatibility between two or more opinions, principles or interests, which can stem from a difference in values. Begin by identifying and articulating values, as this lays the foundation for smooth communication and collaboration. When values are clearly defined, everything else becomes much easier.
### Pseudo-Conflict
Conflicts can take various forms. Sometimes, what people perceive to be a conflict is actually a pseudo-conflict or nothing more than a misunderstanding. Misunderstandings can be a result of misalignments in communication. Take the time to assess each situation carefully, giving yourself and others involved some space and time which can change your perspective. If you can, chat with a friend you trust. You may come to realize that you agree but simply don't understand what the other person is talking about. Take a step back and try again.
### Simple Conflict
An example of a simple conflict is when you say, "Let's agree to disagree. I don't agree that making this decision in this way is in our best interests, but you have presented a really good case." Imagine your team is deciding between using Unity and Godot. If you are not the person working in the engine every day, you might disagree with the switch to Godot but decide to go along with the majority vote because it's not your role.
### Ego Conflict
There are also ego conflicts where things get personal. Someone may say, "I'm the sole expert on this thing. I've got all these extra years of experience," or "I've got this award." Instead of being able to be flexible and open to other opinions and perspectives, no matter where they come from, their ego prevails.
That's often where conflicts become personalized and framed as character differences. There are many ways in which we perceive that this person can never get along with this other person. That's why we need to understand what is actually a conflict. If we come back to the touchstone of our values, the type of conflict might be made clear, and how to go about resolving it can be made clear.
### Resolution
So that takes us to conflict resolution:
a formal structure of policies and processes that everyone agrees to before conflicts arise
the pre-agreed policies can help to depersonalize conflict and the steps to resolution
can set the stage for a third party to support your process
It's best if everyone agrees to these principles and practices in advance. Take an average afternoon, order a pizza for the team, or go onto Zoom and discuss conflict resolution while there is no conflict in the mix. Don't wait for a crisis.
Setting up a formal structure and set of policies can help to depersonalize the process and the steps to a resolution. It drains the intensity and drama out of the conflict. It helps everyone see things more dispassionately, even if at the beginning and the middle, you felt nothing but passion! And it's also allowing the people involved to say, "This isn't about who I am. It's about what's at play or what's at stake."
Conflict resolution also sets the stage for a third party to support your process of resolution if things feel like they're too twisted, tangled, or personal within your studio. A third party can come and look at the processes that you have and actualize and animate them.
So why do conflict resolution? Like anything an illness, infection, strained muscle if you leave it unaddressed, it will get worse. If you avoid conflict by not following a process and giving it time and space (but not too much time and space), the problem can escalate. It can cause a lot of harm sometimes irrevocable harm or harm that ends up breaking things apart.
### Prevention
Prevention of conflict is the best medicine, just like anything that feels painful, hard or difficult. But not all conflict is necessary to avoid, and a lot of times, we grow through conflict! Early intervention in conflict can be beneficial and also vital to fostering deeper collaboration and maintaining a healthy and respectful creative environment.
Sometimes, early intervention is not possible. Sometimes, team members don't agree that something is a conflict, or they don't believe it is yet at the intensity or scale that's worth addressing. And so it festers. How do we do prevention in this situation?
We suggest that you research and understand your individual conflict style in advance. Remember: Conflict resolution isn't just done at the time of conflict. It is something you should anticipate. It's part of life. You don't have to see it as only dire and painful because conflict leads to change and sometimes radical transformation and growth.
Here are some steps to take to start addressing conflict:
1. Research and understand your own individual conflict style.
2. Collectively create a conflict resolution process that suits your studio, your core values and your culture.
3. Decide who will be the contact person or people managing your formal conflict resolution process.
4. Establish a third party (or even two) to serve as a backup in case the contact person is involved in the conflict.
5. Educate each other regularly about the conflict resolution process and encourage changes to it.
> We are a diverse group of individuals gathered in this room today, working together in a coalition despite our many differences. Every person has their own unique journey in life, which leads to differences in opinions and perspectives. However, in our studio work, there tends to be a dominant culture that forms as a result of the relationships we build. That's why we place a strong emphasis on our values, to ensure that they are aligned and become an integral part of our workplace culture.
### More on Personal Conflict Style
There's a lot of research that's been done on conflict because it's so ingrained at the interpersonal, family, neighbourhood, school and community level.
Take a group project in school as an example. You may remember those leading to conflicts. Someone would end up doing more work than others, or someone wouldn't do any work at all. But we rarely asked our teammates why. Maybe they were sick, going through hell at home or simply couldn't understand the assignment. We never knew for sure because we probably avoided those important conversations.
But by examining our own conflict styles, we can start to understand why certain situations may arise. For example, some people may tend to compromise too much when trying to please everyone in the group. Others might avoid conflict altogether, thinking that any disagreement could result in a loss for everyone. Meanwhile, some might be overly accommodating and give in too quickly, leading to feelings of resentment. Then, some compete fiercely due to their competitive nature or upbringing.
Understanding our own conflict styles can help us navigate projects and other situations more effectively. By recognizing our own tendencies and those of others, we can work together toward a more productive and harmonious outcome.
![](/img/tki-scale.jpg)
We don't know where these conflict styles originate, but they can be both beneficial and harmful to our studios. The Thomas Killman model provides a scale to measure these styles in terms of empathy (low to high on the bottom) and assertiveness (low to high on the top), which is worth researching. Understanding your own conflict style and sharing it transparently in meetings can help us learn about each other, increase empathy, encourage assertiveness, and ensure everyone participates fully without being left out.
## Conclusion
Putting it all together:
- **Values** inform decision process and priorities
- **Structure** informs flow of responsibility
- **Goals and impact** help measure success
- **Understanding conflict happens** is the best prevention
Everything comes back to values. Values play a vital role in shaping our decision-making processes and priorities, whether we express them or not. They are always at play, guiding and informing our actions. When we work together in a collaborative and cooperative environment, it is crucial to be transparent with our values, allow them to guide us, and bring us in alignment. This helps us make better decisions, organize responsibilities, and streamline our work. For instance, it can be helpful to have guidelines for note-taking during meetings, creating agendas, and mapping out our plans. It is also essential to be clear about our goals and the impact we want to create. Ultimately, our values drive our aspirations and desires to make a positive impact. Finally, we must acknowledge that conflicts are inevitable, but we can prevent them by understanding their underlying causes.
## Questions to Consider
Here are some things you can think about related to structuring and decision-making within your team. As you discuss these ideas with your team, consider how your intended structure affects roles and decision-making. You should also consider how you can evaluate and communicate your conflict resolution style to your team members. Be aware of your own tendencies and share them with your team.
- Do we all have to come together to make creative decisions equally?
- Do roles and structures encourage hierarchy?
- How does individual agency affect decision-making in more minor decisions?
_This content was developed by [Gamma Space](https://gammaspace.ca) for a 2023 Baby Ghosts cohort presentation. We have summarized and adapted it here._

View file

@ -0,0 +1,30 @@
---
title: Expo Tips
description: ''
category: strategy
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.230Z'
---
# Rocket Adrift Tips for In-Person Expositions
_Thanks Lindsay, Sloane, and Titus!_
- Comfy chairs for folks playing and working the booth.
- Can be pricey to rent so try to bring your own somehow.
- Bring additional branding materials.
- Decoration stuff like table skirts, flowers, and things can help.
- Secondary monitor running trailer with branding.
- Or possibly bringing Steam Decks for more players.
- Dress to impress!
- Cheap t-shirts can be fun.
- Matching jackets are very cool.
- Bring garbage collection and cooler for snacks/drinks.
- B2B (business-to-business) is a tough calculation so make sure its worth the time off and price.
- Are you reaching players?
- Print lots of postcards and business cards!
- Make postcards with a blank space so you can add your contact info if needed.
- You can get them sent to the hotel ahead of time - Henry.
And a special tip from Henry: bring lozenges!

View file

@ -0,0 +1,581 @@
---
title: Financial modelling
description: Introduction to financial modelling for game development cooperatives
category: strategy
tags: []
accessLevel: member
author: Jennie
publishedAt: 2025-11-10T10:42:09.224Z
---
# Navigating Capital
## Financial Modelling and Investment Readiness
**The topic of fundraising can be fraught for folks struggling against capitalism's destructive influence.** This series will walk you through the steps you need to take to be ready to raise money in whatever form you plan to use—bank loans, grants, investments, revenue sharing, preferred share offerings, and more—without losing sight of your collectivist values.
There is much work to do in Canada to transform the funding mechanisms themselves to be more collectivist, such as promoting community funding models, mutual aid networks, and reinvesting profits directly back into communities and worker benefits. This is Weird Ghosts' mission. **In the meantime, game cooperatives implementing practices that align with their values can create better conditions for all workers now.**
## Why do financial modelling?
Financial modelling is one of those things that sounds incredibly complex to many folks outside the investment or finance space. But *every* business can benefit from the exercise, not just those seeking investment—and not only for-profit corporations. The skills you'll develop learning to create a financial model will help you build a sustainable foundation for your studio, whether you're a co-op or share corporation, non-profit or social purpose organization. And it's really not that hard! Hang in there and be patient with yourself. We'll break down everything as simply as we can. If there's something you're not familiar with, you can easily find [definitions online](https://www.investopedia.com/).
In the first section of this series, we'll cover our relationship with money and introduce financial analysis. We'll focus on the investment readiness aspect of the social finance ecosystem, so if you're preparing for impact investment, you're in the right place!
In the other sections, we'll focus on exploring capital-raising alternatives, building a pitch, and learning investor strategy. All of this will lead to investment readiness. Our goal is to leave you with the confidence you need to pursue an impact investment opportunity.
> Investment readiness for us means having the structural capacity to support *collective and community impact* by building autonomous collectives that operate independently of capitalist market pressures by *prioritizing social returns over financial ones*.
>
> Some parts of this series may also be helpful if you are preparing to pitch to traditional investors, VCs, or publishers. Just keep in mind that they will have *very* different expectations of your financial performance.
## Our Relationship with Money
We need to explore our relationship with money before we get into investment readiness. As founders serving a broad audience that includes marginalized folks (e.g., worker-members, players, and communities), we need to start by understanding biases and barriers.
Most marginalized founders will encounter *systemic and interpersonal biases* (related to gender, race, ability, and other factors), which will limit their access to capital, inclusion, agency, power networks, and confidence. **These are not just obstacles but are inherent features of a capitalist system designed to maintain class divisions and inequalities.**
Cultural programming and narratives reinforce the regressive and binary idea that "women shop" and "men invest," which affects the way we perceive money, especially when we have experienced a lack of it.
Marginalized founders tend to have a more complicated relationship with money. This issue can affect your willingness to seek funding, even if the timing is right. Many systemic factors hinder marginalized founders from accessing financing:
1. A lack of underrepresented people making investment decisions
2. Bias from traditional investors, who are mostly white men
3. Historical exclusion from financial education and generational wealth
4. A lack of industry understanding of worker-centric studio structures and sustainable growth
5. An underrepresentation of the types of games marginalized founders want to make
… and more.
This is compounded because less experienced folks tend to be more conservative and pragmatic when pitching their ideas, while those with years in the industry are more likely to sell a vision or a dream. Unfortunately, the scales usually tip toward the latter with investors.
> If you're not selling [hockey stick growth](https://www.investopedia.com/terms/h/hockey-stick-chart.asp), it will be challenging to get a traditional investor to understand your value proposition and impact.
This isn't meant to scare you! But the reality of Canada's funding system is that you will face headwinds.
### Biases and Anxiety
In recent years, funders' mindsets have shifted toward recognizing the challenges faced by marginalized founders and alternatively structured companies. More support is available now, and organizations like Weird Ghosts, Marigold Capital, EDC, Women in Technology Fund, Disruption Ventures, and many others are leading the way. These groups understand the struggles cooperative and worker-centric businesses face in a world that rewards individual entrepreneurs. Unfortunately, these issues are still prevalent, so let's take a look at these biases.
#### Reflection
*Use the following reflective questions to tease out your assumptions, anxieties, and biases.*
- What words come to mind to describe your feelings about investment?
- What pre-existing assumptions do you have about investment and raising capital?
- What words come to mind to describe what success might look like for you after the investment readiness journey?
You won't become an expert overnight. But you can identify your uncertainties about the process of raising capital. Take a step back and understand *why* you feel the way you do.
You may feel nervous about pitching because of your experiences with perfectionism or your relationship with money. **Lean on your support network and resources**, including bookkeepers and finance experts, to help navigate the jargon and provide support and encouragement. Remember, raising capital is possible, and others have done it. Don't be afraid to ask questions, Google, and search Investopedia!
Failure is a natural part of the process. But we can redefine what we consider failure and focus on impact as our goal.
## Accounting
Let's start with **financial statements** and the accounting process. *Accounting* refers to the practice of *recording, tracking, and reporting financial transactions within a business*. Financial statements are a tool to communicate this information. We will cover three types of financial statements: income statement, balance sheet, and cash flow statement.
You might wonder: *I have an accountant why do I need to know this stuff?* Here's why:
- To understand your studio's operations so you can make informed decisions
- To analyze trends over time and make adjustments to the studio or game
- To communicate clearly with stakeholders and investors
Good news: You can do all of these things by *analyzing financial statements*.
### What are investors looking for?
Investors will ask for your financial statements within their first round of reviews to determine whether your business model makes sense. But as a cooperative (or shared-ownership) studio, your financial statements reflect a commitment to equitable distribution and collective benefit rather than merely generating returns for external investors. This is why carefully selecting the investors and lenders you approach and understanding what kind of return they are looking for is critical.
Some questions they may ask:
- **Net profit:** Are you making money now? If not now, when do you expect to?
- **Revenue:** Are people willing to pay for your game or services?
- **Cash flow:** Do you have enough cash on hand?
- **Burn rate:** How much does it cost per month to run your studio?
- **Margin:** What's the cost of making a sale?
- **Growth rate:** How fast is your business growing? (*Growth is likely not something you are pursuing—be ready to answer this by emphasizing how you can scale your **impact***)
- **Debt:** What's your current debt level?
Knowing how investors ask questions and demonstrating your knowledge of relevant terms shows that you are capable and ready to raise capital. Being educated on terminology prepares you to frame community-centric growth and sustainable practices over traditional profit motives.
## Financial Statements
> Looking at your financial statements from the perspective of an investor or lender, what would they think?
Your financial statements will transparently reflect how revenues are reinvested back into the cooperative and the community.
### Income Statement
Your **income statement** (or statement of operations) is a financial document that reflects your operations over a specific *period*. It tracks all the revenue generated from the sales of your games or services and deducts the associated costs. Additionally, it subtracts other expenses that you incur, like general and administrative costs, utilities, and rent. By subtracting all these expenses from the revenue, you arrive at your *profit*, which is the amount of money you've made over that period.
### Balance Sheet
The **balance sheet** represents a specific *point* in time, unlike the income statement, which covers a period of time. You can create a balance sheet or statement of financial position for the end of a fiscal year or any other important date. The standard way to set up a balance sheet is by using the formula: **assets = liabilities + equity**. (Not-for-profit organizations use net assets instead of equity.)
The three categories on the balance sheet are **assets**, **liabilities**, and **equity** (or net assets).
- **Assets:** Assets are tangible items that you own.
- Short-term assets include cash and accounts receivable.
- Long-term assets include equipment and property.
- Investors in traditional businesses prefer you have assets in case of bankruptcy.
- Assets on the books don't determine whether a studio is good or bad! But they can increase investor confidence.
- **Liabilities:** This is what you owe to others.
- Short-term liabilities include credit cards, accounts payable, and lines of credit.
- Long-term liabilities include debt that takes longer than a year to pay off, like bank loans or mortgages.
- If you have a significant amount of debt, creditors with priority have the right to your assets before others. This makes it riskier for investors or lenders who are subordinate to senior creditors, who will receive what is left over after they have been paid.
- **Equity (or net assets):** Equity balances the balance sheet and represents the amount available for an organization to use in the future.
- This amount depends on how you capitalize revenues and includes accumulated retained earnings.
- The yearly profit or loss and any decision to use these funds for future operations can change the net asset account balance.
### Cash Flow Statement
The **cash flow statement** is a core document for investors. It focuses exclusively on cash and shows how it is generated and spent.
If you're paying cash for all your expenses but not seeing revenue immediately (e.g., deferred payments from distributors or platforms or milestone payments from a publisher or investor), you will quickly run out of funds to keep the studio running and pay wages. **You should always know whether there's enough to make it through to the next period.**
The cash flow statement points out exactly when additional capital will be needed. Identifying when and where the cash gap will exist will help you talk to investors about how much cash is required. For example, saying that $50,000 will be needed in one year and $100,000 in two years will help investors understand how they can help fill that $150,000 gap.
## What is a Financial Model?
A financial model is *your best guess at how much money you'll make or need in the next three years.*
A good financial model shows the following:
::list
- Your business model
- The cost to deliver your games and/or services
- The cost to run your studio
- How many people you need
- How you plan to finance your studio
- How much money you need to raise
::
If you've applied for arts council or other government grants, you'll notice that applications and investor requests are similar.
# How to Create Your Financial Model
Financial modelling and scenario planning are the core tools we'll focus on in this section. Getting a handle on them will help you reach investment readiness, project future financial performance, and plan for different ways your studio's business might unfold over months or years.
## Three-Statement Method
The three-statement method for financial modelling is a widely used approach that involves creating three interconnected financial statements: the income statement, balance sheet, and cash flow statement. This isn't the only way—there are many different approaches to financial modelling, with varying degrees of technical and financial complexity. We're focusing on the three-statement method because it uses documents you likely already have (or should create) and because it is foundational to other methods.
Staying on top of your accounting practice—with the support of a professional, ideally—is extremely helpful for identifying trends over time, making informed decisions, and demonstrating financial knowledge to potential funders. It also lets you gauge the viability of a particular revenue model and the potential for a return on investment (ROI), which can guide you in making sound business decisions (and impress investors!). We encourage you to involve everyone in your studio in the process of analyzing and maintaining these documents, so that everyone is educated and able to contribute to financial and investment decisions.
## For Existing Studios
Let's get to creating your model! (New studio? [Jump to the next section.](#for-new-game-studios))
### Step 1: Choose Your Tool
First, pick your tool: Excel or Google Sheets. Whichever you're most comfortable with is fine.
### Step 2: Enter Your Historical Data
Next, in three separate sheets, enter up to three years of financial information for each of the three financial statements: income statement, balance sheet, and cash flow statement.
### Step 3: Analyze Your Financial Statements
So, how do you make sense out of all these numbers? Financial statement analysis involves examining *trends and relationships*.
**Horizontal analysis** (also known as trend analysis) compares financial data over several accounting periods to identify trends and growth patterns.
1. Think about periods that include major events for your studio, such as game launches, funding rounds, or marketing campaigns.
2. Calculate the percentage change from one period to the next for each line item on your income statement and balance sheet. Subtract the old value from the new value, divide the result by the old value, and then multiply by 100.
3. Look for items that show substantial changes and try to correlate these with events in your studio's history (or external events). For example, a spike in revenue might correlate with a showcase featuring your game.
4. To help you pinpoint trends, it may help to create charts and graphs to visually represent these changes over time.
**Vertical analysis** represents each line item as a percentage of a base figure, such as Revenue on the Income Statement and Total Assets on the balance sheet. This helps an investor compare your studio to others of different sizes.
1. Determine the base figure: For the income statement, use Total Revenue; for the balance sheet, use Total Assets.
2. Convert each line item into a percentage of the base figure. For instance, if Total Revenue is $500,000 and marketing costs are $50,000, marketing costs are 10% of Total Revenue.
3. Compare across periods or benchmark against industry norms (if you have access to that type of data, which can be tricky).
**Financial ratios** provide insights into performance. For game studios, which generally don't hold inventory and are rarely profitable in the early stages, the **current ratio** is most relevant. The current ratio assesses your ability to meet short-term obligations (such as salaries and loan payments). To calculate your current ratio, divide your company's total current assets by its total current liabilities.
### Step 4: Forecasting and Assumptions
Create a new sheet and calculate drivers (such as development costs and budget, funding, sales, release timing, and operating expenses, including wages) and ratios as detailed in the previous section. Based on these drivers, create assumptions (scenarios) for the next three years. You'll want to detail the best (unexpected runaway hit), worst (total flop), and most likely (somewhere in the middle) scenarios using information like industry trends, comparables, and economic downturns.
Don't write an essay on your assumptions or reasoning behind your comps. Just be diligent in the way you present this data.
### Step 5: Build Your Financial Statements
Complete your income statement. Your revenue streams likely include sales, subscriptions, grants, and service work. To arrive at net income, include calculated depreciation, interest, taxes, etc.
Build your cash flow statement using cash from operating, investing, and financing activities to determine the closing cash balance.
Finalize the balance sheet. Add the closing cash balance from the cash flow statement.
### Step 6: Linking and Integrating
Link your statements using formulas—changes in one should affect the others appropriately:
- Net Income from the income statement is added to Retained Earnings on the balance sheet, impacting equity.
- The opening line item on the cash flow statement under Operating Activities should be linked to Net Income from the income statement.
- Balance sheet items, such as loan liabilities, are reflected in the cash flows from financing activities on the cash flow statement.
- Asset transactions on the balance sheet, like purchases or sales, are represented as gains or losses on the income statement.
### Tips
Review the financial model from an investor's perspective, questioning your assumptions and changing figures to understand their implications. While traditional investors are looking for your path to profitability, social impact investors are looking for sustainability, the realism of your projections, and how you re-invest profits in the community.
Some common pitfalls to keep in mind are over-optimistic revenue forecasts, underestimating costs, and improper cash flow timing. These mistakes can affect the *realism* of your model and how investors perceive it. Avoid them through sober analysis, diligent research, and periodic reviews.
## For New Game Studios
📊 [Financial Model Template for New Studios](https://docs.google.com/spreadsheets/d/1SIrgtsRBtXY3d6AwkZS18Jes2AvRNOO4IMcEuk2ChoA/edit#gid=**0**) - choose `File > Make a copy`
If you're a brand-new studio (congratulations! 🎉), you need to build a foundation for investment readiness from the ground up. Here's how to do it:
### Step 1: Choose Your Tool
Select either Excel or Google Sheets based on your familiarity and comfort level. Create four separate sheets within your document for the income statement, balance sheet, cash flow statement, and assumptions.
### Step 2: Establish Your Initial Data
Since you don't have three years of historical data, start by estimating your initial costs. **Document all startup costs**, such as wages/salaries, legal fees, software licenses, computer purchases, and any other upfront payments needed to get your studio running. **Detail your funding strategy**, including any initial capital from personal savings, loans, or seed funding you expect to secure. **Estimate revenue streams** from game sales, in-app purchases, subscriptions, and advertising. Analyze market trends and comparable games to make realistic revenue projections.
You can break things down in whatever way makes sense to you—monthly, quarterly, "seasonally" (considering tradeshow season and launch windows), or annually.
### Step 3: Forecasting and Assumptions
Even without historical data, you can estimate future revenues based on market research/comparables, and expected sales trajectories. Consider revenue streams like direct game sales, subscriptions, or in-game purchases.
Budget for ongoing costs such as salaries, rent, marketing, and development expenses. Don't forget to include recurring expenses like software subscriptions and server costs.
Plan the best, worst, and most likely financial scenarios. Use industry benchmarks and market analysis to gauge potential outcomes for game launches and other revenue-driving events.
### Step 4: Build Your Financial Statements
- **Income statement**: Start by forecasting revenue and deducting estimated expenses to calculate your expected net income or loss for each period.
- **Cash flow statement**: Model your cash inflows from operations, financing, and investing activities. This statement is crucial for understanding cash burn rates and when additional funding may be needed.
- **Balance sheet**: Project your assets, liabilities, and equity. Initially, assets might include cash on hand and initial capital investments, while liabilities could include startup loans or credit lines.
> Remember! **assets = liabilities + equity**
### Step 5: Linking and Integrating
Use spreadsheet *formulas* to ensure that changes in one statement are automatically reflected in the others. This will allow you to adjust assumptions and immediately see the impact on all financial statements. For example:
- Net income from the income statement affects both Retained Earnings on the balance sheet and is the starting point for Cash Flows from Operating Activities on the cash flow statement.
- Purchases of assets in the cash flow statement should reflect as asset increases on the balance sheet.
### Tips
Constantly review your model to ensure it realistically reflects possible financial pathways and shows a clear route to sustainability. Regularly challenge your projections by adjusting the assumptions based on new market data or feedback from potential investors.
Be conservative with initial sales forecasts and factor in ample time for development and marketing work. Buffer for unforeseen expenses, such as protracted development time. Finally, new studios often struggle with cash flow timing; meticulously plan for when cash inputs and outputs occur.
You're on your way! Your financial model will be a massively useful tool when you approach lenders or investors and for internal planning. Don't worry about your model being perfect—most indies don't do this work, so you're well ahead of the game. You can and should revisit your numbers often, and you'll learn along the way what aspects serve your studio best.
# How to Prepare for Investment
In this section, we'll focus on investment readiness and preparing to talk to investors. We'll cover creating a pitch deck, building a deal room, and developing an investor strategy. We'll also walk through the stages of investment readiness, from initial preparation to pitching and engaging with investors.
**Set your expectations:** This section won't make you fully investment-ready. We'll focus on preparation, strategy, and pitches, but we won't cover term sheets and negotiations. There's lots to learn, and this is just a starting point.
## Prep
Your first step toward investment readiness is **preparation**. By reading this series, you're already on your way! 🙌🏻
You might be wondering:
::list
- When is the right time to raise?
- How much should we raise?
- What type of security should we issue?
- Wait… what exactly *is* a security?
::
You probably also want to know about the different types of investors and how to prepare your deal room. Let's get to it.
### When
Ideal times to raise funds include when you are planning to scale your dev team or prepare in advance (6-9 months) for your studio's roadmap. Investors look for studios with *validated* ideas, which you can show through community interest, successful demos, or early revenue streams. We can't stress this enough—an idea and a pitch deck are ***very, very rarely*** all you need to land an investment or a publishing deal.
Seeking funds because of an emergency cash shortage or undeveloped idea can telegraph a lack of planning and will likely be unsuccessful.
### How Much
Using your financial model, estimate your cash flow requirements to predict how much you need to raise. Identify all operating costs and milestones leading to your revenue goal. The expenses incurred to achieve these milestones will determine the capital you need to raise.
Traditional venture capitalists (VCs) are looking for big returns. Social impact investors don't seek this level of growth, but they still require you to map out major milestones and outcomes and calculate the capital needed to achieve them.
Ideally, you'll raise enough capital to secure an 18 to 24-month runway. Otherwise, you run the risk of constantly being in capital-raising mode. You want to avoid going back to your investors every year looking for more money.
Make sure you cover everything:
- Salaries, benefits, bonuses
- Rent, utilities, overhead
- Computers, equipment
- Legal, accounting, insurance, supplies
- Working capital, operating cash flow
- Contingency (10-20%)
## Securities
In finance, when you raise money in either private or public markets, you are issuing a security.
> Using traditional financial instruments can perpetuate capitalist norms and practices, even when used by cooperatives. Whenever you can, consider alternative financial practices that reject traditional tools, focusing instead on solidarity economy principles like bartering, shared resources, and common ownership.
The Ontario Securities Commission defines a security as a *financial instrument that is negotiable and holds some monetary value*—typically either debt or equity your studio issues. If you are considering issuing securities, it is essential to comply with the regulations of the security commission in your jurisdiction (e.g., [Ontario Securities Commission](http://www.osc.gov.on.ca/) ) and seek legal advice. There are various exemptions for accredited investors, offering memoranda and crowdfunding, under which you can file your securities with the OSE, allowing you to raise capital from different groups of investors.
### What type of security should we issue?
To simplify things, we'll cover two main types of capital here: traditional debt (a loan) and equity (where an investor buys shares).
While cooperatives cannot access equity capital from outside investors in the same way as traditional share corporations, they do have avenues to raise capital through member shares, investment shares, or preferred shares. The specific options available depend on the individual cooperative's structure and the relevant federal and provincial legislation.
| Debt (loan) | Equity (buying shares) |
| ---------------------- | ------------------------------------ |
| Lower risk | Higher risk, higher potential return |
| First money back | Lives and dies with company |
| First lien on assets | Unsecured |
| Negative covenants | Board governance |
| Inexpensive to company | Expensive to company |
So why is debt considered a lower risk for an organization to issue?
#### Debt considerations
Debt financing is **predictable** and **finite**. When you take on a loan, the terms are clearly defined from the beginning, including the duration and the interest rate, which is often fixed. This clarity makes forecasting much simpler. You are obligated to repay the loan amount (principal) along with interest over a set period of time. Once you fully repay your loan, the obligation ends you only owe the principal amount and the accrued interest, nothing more. The lender does not gain any ownership in your company.
The primary source of loan repayment is generated cash flow. Lenders typically engage with businesses during the validation stage, assessing the likelihood of repayment based on projected revenues. Lenders consider the "Five Cs of Credit" when evaluating your creditworthiness:
1. **Character:** This refers to your track record of repaying debts. Lenders will look at your credit score.
2. **Capacity:** Lenders will consider your income and debts to determine your capacity. They want to ensure that you have the cash flow to cover loan repayments in addition to your other expenses.
3. **Capital:** This refers to the funds you've invested in the studio or personal assets that could be used to repay the debt if needed. It is sometimes referred to as *skin in the game*.
4. **Conditions:** The broader economic picture, including industry trends and market competition. During economic downturns, they may tighten lending standards.
5. **Collateral:** These are assets that the lender can seize if you fail to repay the loan.
#### Equity considerations
Equity financing means giving up a part of your studio for capital. This often leads to sharing control and profits. Equity investors typically seek higher returns than lenders and can make financing costlier, especially during periods of strong growth. An investor with a 5% stake in your studio will get 5% of profits or the sale price. Selling equity dilutes your ownership stake in the studio, which can impact your control over business decisions.
Equity investors differ from project funders (like publishers) as they focus on long-term potential rather than immediate project outcomes. These investors, including angels, VCs, and corporate venture funds, seek studios with scalable, exponential growth potential.
Equity investors sometimes come with more than money. They may have resources like industry contacts and strategic advice, which may open up new opportunities for your studio, depending on your goals.
You don't have to repay investors, but they aim to earn dividends and reap share value increases. Dividends are paid periodically from profits, while share value grows as the company succeeds.
You need to find the right funder at the right development stage. Both angel investors and VCs invest during the concept validation stage. As the project matures, publishers and investors become more viable, offering larger sums but often requiring a share of revenue or equity. Crowdfunding is also an option, ideal for validating market interest and securing funds without giving up equity. For earlier stages like ideation and discovery, many studios rely on self-funding, jams and competitions, arts council grants, and accelerator or incubator programs like Baby Ghosts. These are opportunities to build and validate your demo.
> **The most effective way to fund your business is through sales revenue.** Using profits for growth is the least expensive form of capital. If you can swing it, this is the way.
> [Jason Della Rocca](https://dellaroc.ca/) is a wonderful industry resource on the topic of funding and pitching to mainstream VC studio and project investors. Search for his articles and videos if this is the route you're interested in. [Here's a list of game-industry VCs.](https://nextgengamingclub.com/#investors)
### Types of Securities
Here are a few of the many different types of securities you might consider. Some are more relevant to co-ops ([investment shares](#investment-shares), [preferred shares](#preferred-shares), and [SEAL agreements](#shared-earnings-agreement)).
#### Debt
A lender provides capital with the expectation that it will be paid back in a specific time frame (term), with an agreed-upon markup to compensate them for their risk (interest rate).
#### Convertible Debt
A type of debt that can be converted into other types of securities (i.e., equity) based on predefined criteria.
#### Preferred Shares
Preferred shares provide dividends at predetermined rates ahead of common shareholders. They typically lack voting rights and do not confer the title of co-ownership but provide greater security during liquidation. Your articles of incorporation should outline the specific terms of the preferred shares.
#### Investment Shares
Investment shares are a relatively new option that provides cooperatives with an additional means to raise capital beyond traditional member shares. Investment shares can be issued to members and non-members, although you can specify that they are made available only to members in your coop.
Unlike member shares, which grant democratic voting rights, investment shares generally do not confer voting privileges. This maintains the cooperative principle of democratic member control.
Provincial legislation may limit the percentage of investment share capital that can be held by non-members. This ensures the cooperative remains primarily owned and controlled by its members. You can allocate a portion of your surplus as dividends on investment shares to provide a financial return to investors.
[Information Guide on Co-operatives](https://ised-isde.canada.ca/site/cooperatives-canada/en/information-guide-co-operatives) from [Innovation, Science and Economic Development Canada](https://ised-isde.canada.ca/site/ised/en)
#### Community Bonds
Community bonds are a way for community organizations to raise capital from local investors to invest in local issues. They are useful for organizations with a community-centred impact. One prime example of this is the [Center for Social Innovation's Community Bond](https://socialinnovation.org/product-service/community-bond/), which was one of the first community bonds that became notable in the Canadian ecosystem.
#### Social Impact Bonds
Social impact bonds (SIBs) are a type of security where investor returns depend on achieving social impact outcomes. Investors provide upfront capital, and the government is the outcomes payer. If positive changes are demonstrated, the government pays investors a return based on the level of change. SIBs are most suitable for organizations with broad impact and measurable social return.
#### Revenue Share Loan
Revenue share loans are a type of security that's not listed on your books as a traditional loan. Instead, repayment is based on the revenue you generate. Funders that offer this type of financing include Clear Bank, Marigold Capital, and Youth Social Innovation Capital Fund. Revenue share loans may be suitable for organizations projecting stable revenue flow.
#### Common Shares
Common shares represent equity ownership, providing shareholders with voting rights and the potential for dividends. These shares often reflect the company's value, fluctuating with its financial performance. Shareholders benefit from company growth but also bear risks, including potential loss of investment.
#### Simple Agreement for Future Equity
A Simple Agreement for Future Equity (SAFE) is an investment tool for startups that offers future equity in exchange for immediate funding. It's simpler than traditional convertible notes, as it doesn't accrue interest or have a maturity date. Investors receive equity based on the company's future valuation, typically during a funding round.
#### Options
Options are contracts granting the holder the right, but not the obligation, to buy or sell an underlying asset (like stocks) at a specified price before a set expiration date. They're used for hedging risks or speculative investment strategies, often included in employee compensation packages for startups.
#### Shared-Earnings Agreement
Similar to a revenue share loan, a shared-earnings agreement (SEAL) is repaid through revenues. However, the total amount that can be recouped is capped, and payback only triggers once founder salaries have been paid. [Weird Ghosts uses this type of agreement.](https://weirdghosts.ca/blog/how-we-make-investments)
## The Deal Room
Get all of your documents ready for the deal room. (You should also create pitch materials that cater to different situations that you may encounter during the capital raising process.)
A deal room is just a collection of documents that are associated with your offering. It could be a virtual folder on a platform like Google Drive, Proton Drive, Dropbox, or your own secure website.
The deal room typically includes:
::list
- Your pitch deck
- Financial history
- Financial model
- Team bios and resumes
- Competitive analysis
- Business plan
- Impact model
- Testimonials, reviews, and press releases
::
Keep your deal room organized with clear subfolders and document titles. It is good practice to include the document title on each page (in a header or footer). Imagine an investor printing it out!
## Pitching
So! Your deal room is ready, and you are keen to approach investors. But how do you create the perfect pitch? Sadly, even with all the templates and tips out there, no formula for guaranteed success exists. The style and content of your pitch will depend on your studio, impact model, and even your personality.
Something to think about: A pitch is more than just a presentation—it's a dialogue. Open a conversation, and don't get defensive about your studio. If it feels like an investor is pushing your buttons, remember that any critique is *valuable and constructive*.
### Types of pitches
You'll find yourself pitching in many different situations. There's the elevator pitch, the platform pitch, the quick pitch, the investor pitch, your leave behind, the community pitch, the demo pitch, the conference pitch, and more.
Be prepared to present your studio in different time slots. Have various pitch variations ready in case an investor has either five minutes or an hour to hear you out.
We won't dig too deep into what slides you should include—online resources are abundant:
- [Glitch's Video Game Pitch Decks](https://heyglitch.notion.site/Pitch-Decks-f56e38c13fe6417f8379859e74367e1a)
- [Rami Ismail's Pitch Template](https://ltpf.ramiismail.com/pitch-template/)
## Investor Strategy
You're finally here. You're ready to talk to investors. 🙌🏻
In this section, we'll cover getting ready, finding investors, and tracking leads.
### First Steps
Start getting ready for your capital raise at least **six to nine months prior to the actual need for funds**.
#### Are You Ready?
The first step is to psychologically prepare for this process. It can be deflating to face rejection, and that is more than likely what you will face for *months to years* as you pursue funding. Protecting your mental health is more important than anything.
One strategy is to remember that **"No"s are valuable opportunities** to refine and tune your offering. They are not judgments on whether your studio is a good business (or if your game is worth making), but reflections on the state of the funder and their own evaluation framework. That's it!
Another difficult but useful tactic is **decoupling your sense of personal value** from what you're pitching. This will help you separate inevitable rejections from your sense of self.
**Ensure you have a support system in place:** A therapist if affordable, family if feasible, friends outside the industry, peers such as other studio founders, advisors, and industry mentors. Don't go it alone. Consider an approach where investment decisions are made collectively by all members of the studio.
Finally—and this may seem sort of sad—**prepare for the worst.** While you're optimistic about securing funding, you need a backup plan in case things don't go as planned. Think about what you'll do if you're unsuccessful within three months, six months, one year, or two years. Will you pivot your strategy, close the studio, or put it on hold and return to your career? Being clear-eyed about these worst-case scenarios will help you make informed decisions and stay in control of your studio's future.
So… are you ready? And how would you know if you were? 🤔 Here's a rundown of things you should ***know*** before you go after your first investor.
#### Is Your Studio Ready?
**Is the business set up?**
- Have you incorporated your cooperative?
- Do you need to register in additional jurisdictions?
- Do you have a [business plan](/articles/6.business-planning)?
- Does the studio have its own bank account?
**Is your game ready?**
- Do you have a working demo?
- What is its initial feature set/scope?
- Do you have a roadmap or project plan?
- How does this initial game contribute to your studio's overall strategy?
**What's your marketing approach?**
- Who is your target player?
- How do you plan to reach them?
- How does a customer's life cycle change over time?
- What are the potential player segments to explore?
- Do you have a reliable player feedback loop?
**Have you achieved traction/validation?**
*e.g., feedback from playtesting or beta/pre-early access, attention on announcements*
- How are you measuring traction?
- What traction have you achieved to date?
- How can publishers amplify your traction?
- How will your current traction translate into long-term growth?
**How will you position your game in an oversaturated market?**
- What is your target market/audience? Why does it appeal to them?
- How will you reach your target market initially?
- How can your game fit into a publisher's marketing strategy?
- How can your game work with a platform's distribution strategy?
- How will you gain and protect your market position?
- How is your game different from others in your target market?
#### Is Your Team Ready?
**Do you have the right team?**
- Are all members' or founders' values aligned?
- Do you trust each other and work well together? Have you collaborated before?
- Does anyone on your team have prior experience with raising money or shipping games?
- Will you hire contractors, or is that counter to your collectivist values?
- Have any team members garnered critical acclaim?
- Do you have a producer to help with the publishing process?
- Do your collective skills cover creative, technical, and business areas?
**What is your planned governance strategy?**
- What is the appropriate governance structure for your company?
- How will you incorporate diversity, equity, and inclusion from the ground up?
- How will you ensure your values are incorporated into operations?
- How do you plan to adapt your company's culture and structure as your team and company scale?
- How do you plan to compensate members?
**What impact does your team hope to achieve?**
- What motivated your founding team to start this studio/produce this game?
- How do you [measure impact](/articles/results-flow)?
- What impact have you achieved to date?
- How do you hope that your customers and community will respond to/contribute to your impact goals?
#### Are Your Financials Ready?
**How much money do you need?**
- What is your target fundraising amount?
- How will the funding be applied to your milestones?
- How will you return value to your community, members, and/or investors?
### Networking
The bad news is that finding investors takes work and is not an equitable or accessible process. Warm leads (connections to people who know about you through their network) are the standard way to approach money people—but if you don't already have those established networks within the industry, what can you do?
Lots of indies hate hearing this, but you're going to have to network. There are all sorts of virtual investor events, community events, and industry events (local and international) where you can meet potential investors. (These events are not *just* for catching up with friends, although that is a lovely perk!) You may need to step outside your comfort zone and practice new skills to create and nurture business relationships.
This means:
- Researching and approaching people you don't know
- Asking acquaintances or second- and third-degree LinkedIn connections for introductions
- Getting involved in industry associations (e.g., Interactive Ontario, New Media Manitoba, DigiBC) and getting to know its board members, advisors, coaches, and members
- Working on your conversational and soft-pitching skills
- Being diligent about follow-ups and using the right channels (email, phone, Discord)
- Listening and responding when investors tell you what they're looking for
> **Share the wealth:** Being open and generous with your connections is a way to break the cycle where only those already connected or privileged enough to have such networks can easily find investment.
### Researching
Once you have an idea of what type of investor you are looking for and where to find them, you can start your search online using Google, LinkedIn, Twitter, and any other social or professional platforms you're on.
Use these tools to identify the investor's investment history and get a sense of their preferences. Ask people in your network about their history and relationship to gauge their track record and the types of investments they are more likely to consider.
You can also look into an individual investor's personal and professional interests, recent events they attended or spoke at, and their relationships with others. You can find this information on LinkedIn or through pictures to identify them if you meet them in person. While it may seem a bit intrusive, you want to gather as much information as possible about the investor before meeting them to make a good impression and tailor your pitch to their interests.
### Tracking
**Stay organized.** Implement a system to keep track of who, what, when, where, how much, stage, last interaction, likes, connections, and other relevant information. You can use a dedicated CRM like Pipedrive or HubSpot, an Airtable base, or even a Google Sheet.
**Tailor your materials** to the investor you are meeting. Make slight alterations to your deck based on who you're talking to. Add the investor's logo to the first slide of your deck to show that you have tailored your presentation to them.
**Arrive over-prepared.** On the day of your pitch, come with your deck ready in USB form, on your computer, in your email, in a link you've shared with the investor, and in a hard copy if your pitch is in-person. Bring something to write with, and be early. These are table stakes.
**Decide how you plan to frame the conversation**, whether it is an introductory chat or a formal pitch, and who will lead it. How do you want to end it? Is it with a specific ask?
**Follow up immediately.** Be gracious and succinct in your email, and state your next steps. Keep the to-dos on your end.
**Update your tracking system!** After you walk away or click End Meeting on Zoom, note down everything you can remember about this person. Articulate what milestones you need to trigger that next meeting with them.
In your CRM, you can set a reminder for the timing of your next follow-up.
### What to Expect
- The goal of your first meeting is really to get them to like you and want to meet with you again.
- The second meeting is when you'll get through that official pitch.
- Then, the third meeting is when you really dive into the details.
This process requires nurturing and many meetings over months or even a year, depending on the funder.
We covered a *lot* of ground, and you may be feeling overwhelmed or nervous. Remember, this is a long-term process, and you don't have to do it all at once (or all alone!). Take your time, [reach out to us](mailto:hello@babyghosts.fund) for support, and remember the values and principles you're buiding on as you navigate capitalism as a cooperative.
- - -
*With thanks to SVX and Adaora Ogbue for the inspiration for portions of this section.*

View file

@ -0,0 +1,143 @@
---
title: Game Discovery Toolkit
description: ''
category: strategy
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.227Z'
---
# Summary: The Complete Game Discovery Toolkit
_[Here](https://newsletter.gamediscover.co/p/in-depth-a-discovery-playbook-for) is a recent newsletter from GameDiscoverCo. updating some of the below!_
This e-book comes with a Plus subscription to the [GameDiscoverCo Plus newsletter](https://newsletter.gamediscover.co), which we highly recommend. These are just my notes on the high points of the book!
### Pre-release priorities
#### Initial Steam page launch
When you're planning on launching games on Steam, here are the most important steps you need to take for a successful initial Steam page launch:
- always try to include a gameplay video
- majority of screenshots should be of in-game assets
- push your Discord server in an obvious place on the page
- make sure your Steam tags are in place and are subgenre-specific enough
- put gameplay GIFs in your description
- use the 'capsule' description to clearly explain what you do in the game (including genre/subgenre!)
- ideally, you should have the Steam page up 6 months before the games release at absolute minimum, and 12-18 months is even better for accumulating wishlists
- focus on the growth of follows/wishlists
- remember that wishlist spikes don't always map to sales
#### High priority tasks
- organic streamer outreach
- creating video trailers (aim for 3 per cycle: launch, release date announce, and release. Two can be similar, and include as much gameplay as possible)
- managing your Discord server/community interaction on Steam (including regular dev updates!)
#### Medium priority tasks
- press/media outreach
- getting featured in Steam pre-release sales
- maintaining active social media accounts (TikTok, Reddit, and Imgur are highest priority, but don't forget Twitter)
- creating a demo for Steam festival or for long-term posting
- conducting basic marketing tracking
- considering paid ads or streamer inclusions for visibility during launch
#### Low priority tasks
- attending physical events
- creating physical paid merch
- running paid ads for wishlist acquisition (unless it's a high-priced game)
- submitting to Steam curators
- implementing detailed marketing tracking
- maintaining lower-priority social media (like Facebook)
To improve your game's success on launch, you need to find the fans of your game, care for them, and nurture them as you develop it.
## Post-release strategies
Much is set after the game's launch - it's hard to turn around ratings and general level of interest after the first 2-4 weeks. But here's what you can do:
- rely on word of mouth over time - if it's a great game, people will talk
- be smart about taking advantage of sales and discounts
- have a regular update structure to the game if you can
### Marketing beats
These are the key moments in your game's lifecycle that you should capitalize on:
1. Initial announcement - 6-24 months before release - as early as possible
- press release
- trailer with gameplay
- Steam page
2. Steam NextFest Demo/Appearance - 3-9 months before release
3. Release date announcement - 4-8 weeks before release
- new visuals
- fresh trailer
4. Game release
- "Available now" announcement
- new trailer
- streamer, press, and social blast with as many review keys as possible
5. Post-release beats
- updates and DLC
Paid DLC can be a great way to increase the value of the long tail. Don't count on base game buyers to come back for DLC, but first-time buyers might get the bundle. The earlier DLC is launched the better - it can be marketed on the game's title screen and alongside sale discounts.
### Pricing
Games should be priced at least $20 or 18 EUR. You should price regionally and tactically (for example, the price needs to be lower in China and Russia). True fans are less price sensitive - your job is to accumulate these. Price is not a driver - people buy games because they fulfill a need, not because they're cheap. You won't sell more copies at a lower price point, and a higher price can equal higher perceived quality. The exceptions to these rules are very short games, hobby games, 2D puzzle games, and DLC-driven games.
### Maintaining the long tail
1. Make a game that meets and manages the expectations of the people who are planning to buy and play it. Promote a clear pre-release understanding and execute on it.
2. High review scores correlate to higher sales on Steam.
- Good word of mouth leads to better reviews.
- High review scores on the Steam page motivates buyers.
3. Make a streamable game.
- Open the door to user-generated content and player creativity. The majority of games that do well in the long term allow new content.
- Retain players (for replayable, updatable games) through updates, DLC, social-centric gameplay, and discourse.
- Put your game on sale to turn wishlists into sales - be methodical about discount timings and amounts.
## Post-release discount strategies
Most devs don't strategically discount, but discounts can be a big post-launch driver.
1. Frequency: Discount at every available opportunity. Find sales through Steam, and platform reps.
2. Amount: Gradually increase discounts. For example, Overcooked introduced discounts down to 50% over 2 years.
3. Aggressiveness: You can potentially make more cash with aggressive discounts.
### Steam tags - best and worst genres
Ranked from best median sales to worst: 4X, roguelike deckbuilder, city builder, political sim, RTS, management, online co-op, tactical RPG, Metroidvania, turn-based strategy, dating sim, roguelike, farming sim, hack and slash, JRPG, psychological horror, dungeon crawler, visual novel, point and click, action RPG, beat 'em up, walking simulator, FPS, survival horror, rhythm, interactive fiction, tower defense, side-scroller, platformer, puzzle platformer.
## Discovery
Expect to make 2x to 5x your first week sales in the first year.
In terms of wishlists to sales expectations, the median is 0.2 sales per wishlist in the first week on Steam (0.36 average).
Buzz outside Steam counts for a lot. Titles that launched with over 10,000 wishlists but low recognition (1 out of 10) converted at a tenth of those with high recognition (8 out of 10). Press, streamers, and vibrant communities are important.
### Steam's week 1 to year 1, 2, 3 revenue
- Average multiple for Month 1: 1.57x
- Average multiple for Year 1: 4.52x
- Median multiple for Month 1: 1.47x
- Median multiple for Year 1: 4x
### Steam's reviews to sales ratio
Using the New Boxleiter method, the average number of sales per review is 63, with a median of 58. The non-outlier range is 20 to 60 sales per review for new games launched after 2020. (note: [here's an online tool](https://steam-revenue-calculator.com) for estimating Steam sales based on reviews using the Boxleiter method)
### Steam's net revenue compared to gross
Determining revenue involves factoring in the average "regular" price, how often it was on sale and by how much, the Steam platform cut, refunds, and VAT. Realistically, this is 30-50% of the optimistic gross number.
#### Refunds
Why might your refund rate be high?
1. The game doesn't make a good initial impression. You can do something about this!
2. The country mix you are selling into: China refund

View file

@ -0,0 +1,298 @@
---
title: Impact Measurement
description: >-
A step-by-step guide to creating an impact measurement framework for your
indie game studio.
category: impact
tags: []
accessLevel: member
author: Weird Ghosts
publishedAt: '2025-11-10T10:52:42.627Z'
---
# Developing your impact measurement framework
## Measuring and Managing Your Impact
Gauging success in a traditional, profit-centric business can be done easily using established and readily understood financial measures. Impact performance is more difficult to identify and quantify. How do you track changes in attitude, knowledge, and behaviour? Collecting and assessing this data requires a structured approach. You need an **impact measurement framework** (IMF)!
An IMF puts your results flow _theory_ to the test. It answers the questions: How achievable are our outcomes? Does our timeline make sense? Are our strategies working? And lets you adjust your activities as you go to focus on what gets you closer to your goals.
It's also a really handy resource for developing your business plan, setting your roadmap, and determining more challenging future targets.
We've previously covered [setting goals, defining impact, and creating a results flow](/impact-tools/results-flow), and now we are learning how to make a plan to achieve our desired outcomes and measure our progress toward them. We are **layering tools on top of each other** to create a framework for turning our dreams into measurable impact.
Together, these tools will make it possible and easier for you to:
- Pitch for social finance (and traditional) investment
- Align your activities with your goals
We will walk you through the elements of an IMF, dig into how to create and evaluate indicators and get you started on designing a custom framework in this article. Let's get to it!
## Why use an IMF?
Can you get away with not having an IMF? Sure pretty much every indie studio does. But they're not deliberately working towards positive social impact like you are. There are three core reasons you should invest in creating and maintaining an IMF if you are impact-focused:
### Accountability
Your **funders** especially social finance investors will expect tracking and reporting. Your **stakeholders** (employees, workers, community of players/supporters) expect you to operate and create games that reflect your stated values and goals. Your IMF allows you to identify, assess, and involve these stakeholders.
Resistance to this is understandable! Isn't this just a capitalist, colonial tool for assigning value? It can be, but you can use it as a tool for yourself and your community instead. This is great to acknowledge and critique as you are developing your IMF. Be _explicit about who is centred in your work_ it will help you align with the right investors whose priorities are the same as yours. Think about who your stakeholders are. You need to measure different things depending on who they are and what they need. What is important to them?
### Building on your results flow
The results flow identified the impact you want to have in the world and the activities you need to do to achieve that change. But it's a fairly general tool. Each outcome describes whom you wish to impact and what outcome you hope for. But how do you move from wishes and dreams to making all this happen?
You need to build accountability into your plans. **Accountability leads to a deeper analysis of what you are doing to make change**, and how your activities actually lead to the changes you expect. Your results flow forms the basis of this accountability.
### Evidence
An IMF allows you to gather evidence that tells you if you are living up to your intentions at any moment so you can determine if the work you are doing, the audience you are serving, and the games you are designing truly put you on the path to fulfilling your mission. This evidence allows you to see what you're doing that has a positive impact, and what is ineffective or harmful.
### Improved activities
This evidence makes it possible to assess **how effective** specific strategies are at helping you meet your goals so you can adjust your activities, seek new resources, and better define your expected outputs. It allows you to **refine the design** of your games and make decisions that directly support your studio's ultimate outcome.
### Why not use an existing tool?
While there are out-of-the-box applications out there ([Sopact](https://www.sopact.com), [B Impact Assessment](https://www.bcorporation.net/en-us/programs-and-tools/b-impact-assessment/), [Unit of Impact](https://unitofimpact.com), [Cigarbox](https://www.cigarbox.nl), [CSI Impact Dashboard](https://impactdashboard.org)), there's no universal standard framework or set of metrics for social impact. Systems such as [IRIS+](https://iris.thegiin.org(https://iris.thegiin.org/) (which provides a taxonomy of standardized definitions) can be used for inspiration but can be overwhelming and hard to implement for a small studio. We're going to go the custom route instead.
We believe your framework just like your outcomes should be carefully designed around your needs and desired outcomes, and heavily informed by the full spectrum of your stakeholders and community (_including your employees!_).
## Understanding the IMF
What exactly does an IMF look like? They take many forms, especially web-based applications like those mentioned above. We will look at a spreadsheet version and an Airtable version today, but you can use any set of tools and technology that is comfortable for you. The main thing is to define your elements carefully and collect data in a structured, sustainable way.
At a glance, your IMF will show:
1. Progress towards change and impact in measurable terms
2. Documentation of that change
Here is what (a portion) of two real IMFs looks like:
![IMF spreadsheet example](/content/imf/imf-spreadsheet.png)
![IMF Airtable example](/content/imf/imf-airtable.png)
When designing your framework, the goal is to:
- **Identify the right indicators to measure your outcomes**: What change are you measuring?
- **Describe a plan for how to collect data**: What are your measurement tools? Who collects data, and how often? What is automated?
### Elements
Here's a quick overview of the core elements of an IMF:
| Element | Description | Example |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| **Outcomes** | The goals you have committed to being accountable for - copied straight over from your results flow. | Employees feel critically engaged with the collective creation of games within the company. |
| **Indicators** | Descriptions of changes, specifying exactly what is to be measured. | Percentage of employees who make meaningful contributions to the design process. |
| **Responsibility** | Simply, who will collect the data? | Chief operating officer |
| **Frequency** | How often you will collect the data. | Monthly |
| **Data sources and tool** | Where will you get the data, and how will you collect it? | Observation of studio employees |
| **Baseline** | What your numbers look like at the beginning of your studio, a new project, or whenever you start collecting data. | 50% |
| **Target** | The desired situation, expressed in terms of the indicator. | 100% |
## Building Your Own IMF
Before getting into more detail about each of the above elements, let's set you up with a template so you can start roughing your information.
If you want to use a spreadsheet, you can access our template here: [Impact Measurement Framework - Blank Template](https://docs.google.com/spreadsheets/d/1zHDdHi7EuYCVdHw_1LINMF5Ty9n1bu-XEQxn1Z5chnk/edit##gid=293015620) (Google Sheets). Select "Make a copy" in the File menu to save a version to your Google Drive. If you prefer Numbers or Excel, you can download your copy and import/open it in one of those applications.
At Weird Ghosts, we use [Airtable](https://airtable.com) to manage our IMF. Airtable is similar to a spreadsheet application but works more like a database and includes powerful features like data modeling, automations, and custom views and interfaces. You can use our template here: [Impact Measurement Framework](https://www.airtable.com/universe/expFQ8hvE8mapTVot/impact-measurement-framework?_gl=1%2A1gkbibu%2A_ga%2AMjAwMDc5MjY0Mi4xNjg4MTUwNjQw%2A_ga_HF9VV0C1X2%2AMTY4OTg3NDQ3My42LjEuMTY4OTg3NDU2Ni4wLjAuMA..). Click "Use template" at the top, or for a sneak peek first, click "Explore the base" then "Copy base" in the bottom left corner.
Let's start adding some info!
### Outcomes
The first thing you'll want to do is populate your template with the outcomes you've identified as those you're ready to be held accountable for. We suggest looking through the outcomes in your [results flow](/impact-tools/results-flow) and selecting one or two per timeframe (short-, medium-, long-term). Just copy them over into the appropriate spot. (In the Airtable template, add them in the Outcomes table.)
### Indicators
Indicators are next. You'll be spending some time brainstorming, refining, and reviewing these, but you can start by jotting down ideas that seem doable in the near future. Let's get into more detail about what makes an effective indicator.
Aim to identify two or three indicators per outcome, with a mix of qualitative and quantitative indicators, to get a wide view. Remember, an indicator is a neutral **measure** (quantitative) or **descriptor** (qualitative) of a change. It specifies the value to be measured to track the expected change. They allow you to understand _how well_ you are moving toward change or where you are on the "thermometer." It describes _progress_.
| **Quantitative** | **Qualitative** |
| ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Statistical measures | Perception, opinion, or quality |
| Number, frequency, percentile, ratio, variance | Stories, presence/absence of certain conditions, quality of participation, level of user satisfaction |
| e.g.: _Percentage of core funders with an adequate internal action plan for addressing the diversity of applicants_ | e.g., _Average value of the sense of relevance to users' lives_ |
Indicators can come from internal or external sources e.g., data collected through your game, user surveys, and community engagement, such as Discord or Twitter. You don't have to focus on traditional marketing metrics like clicks, likes, predatory interactions and addiction-based mechanics.
Privacy and consent are essential considerations in all these methods. Remember to consider what is _ethical_ and _legal_ when collecting data from your users. Always be transparent about what data you're collecting and why, and give users the option to opt-out.
In addition, different types of games may require different data collection approaches: a mobile game might collect different data than a console game, and a single-player game will have different considerations than a multiplayer game.
#### Evaluating your indicators
As you draft some indicators, evaluate them based on the following questions.
- **Validity**: Does the indicator actually measure progress toward the expected result?
- **Reliability**: Will the data be consistent over time and readily available?
- **Sensitivity**: When the result changes, will the indicator also change accordingly?
- **Simplicity**: How easy will it be to collect the data?
- **Utility**: Will the information collected be useful for your programming and decision-making?
- **Affordability**: Do we as a studio (along with partners) have the resources to collect the data?
We also recommend you use the [SMART goals framework](https://asana.com/resources/smart-goals) to test them:
- **Specific** - narrow and accurately describes what will be measured.
- **Measurable** - can be counted and observed the same way every time.
- **Attainable** - achievable and affordable.
- **Relevant** - aligned with your ultimate outcome.
- **Time-bound** - attached to a timeframe.
Ask yourself:
1. Does this indicator directly measure the outcome?
2. How easy is it to collect this indicator?
3. When the outcome changes, will the indicator change as well?
Spend time brainstorming, editing, and sharing your indicators with your team. Focus on the outcomes you said you'd hold yourself accountable for achieving  not your whole results flow.
A good indicator **makes it easy to know at a glance that changes have occurred**.
#### Examples
Here are several short-term outcomerelated indicators for a fictional game studio whose ultimate outcome is "People feel connected to their devices in a way that supports their health and wellbeing":
| Outcome | Indicators |
| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Coworkers feel critically engaged with the collective creation of games within the company | - Percentage of coworkers who actively contribute to the design process<br>- Employee sentiment around their involvement in collaborative game creation processes |
| Players are aware of apps that encourage and allow healthy interactions with their phone | - Percentage of self-described gamers in the sample who can name at least one app that promotes healthy phone interaction<br>- Frequency of health-focused apps being featured in popular app storefronts<br>- Volume and tone of media coverage of apps that encourage healthy phone interaction |
Here are some for a studio whose ultimate outcome is "LGBTQIA+ identities are understood and accepted in games, mirroring a society that celebrates diversity and inclusion":
| Outcome | Indicators |
| ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Players gain exposure to diverse characters and narratives | - Percentage of players who can recall diverse characters and narratives in the game<br>- The number of diverse characters and narratives represented in the game |
| Community members feel safe and accepted, fostering a sense of belonging | - Percentage of community members expressing a sense of safety and belonging<br>- Number of reports of harassment or toxic behaviour<br>- Frequency and quality of positive interactions in community spaces (forums, social media, etc.) |
Here are some more ideas about what you could measure based on the topic area of your outcomes:
**Player experience and satisfaction:**
- Average user-reported satisfaction score.
- Ratio of positive to negative feedback.
- Trend in sentiment scores from feedback, reviews, and social media.
**Community engagement and health:**
- Total active community members.
- Average engagement in community activities (Discord messages, event participation, newsletter opens).
- Measures of community cohesion versus toxicity.
**Inclusivity and diversity:**
- Average inclusivity rating from user feedback.
- Diversity of user base demographics.
**Environmental and sustainability impact:**
- Total energy consumption (servers and game usage).
- Amount of waste from physical game production.
- Impact of environmental offset actions.
**Access:**
- Proportion of players requiring accessibility features.
- Number of scholarships or grants for underrepresented developers.
**Revenue and financial metrics:**
- Total revenue, in-app purchase income, subscription income.
- Total costs (development, marketing, support, server maintenance).
- Profit margin and return on investment.
**Gameplay metrics:**
- Total, daily, and monthly active users.
- Average session length and frequency of play.
- Player retention and churn rates.
### Challenges and limitations
Be aware of potential problems that may influence the accuracy and reliability of your indicators. Here are some areas to consider:
#### Bias
Bias can creep into your measurements. It might be introduced during the data collection process, especially if the data is self-reported by users. Consider methods to mitigate the impact of bias, like random sampling or anonymizing feedback.
#### Quantifying impact
Quantifying the impact of your game, particularly in terms of social outcomes, can be challenging. _There's a reason it's not mainstream!_ Metrics like player satisfaction and community engagement can be measured relatively directly. Still, others, such as the influence of your game on players' perspectives or attitudes, can be more difficult to capture.
Using a variety of qualitative and quantitative measures helps address this, as could using proxy measures. For instance, if you want to track increased empathy in players due to exposure to diverse narratives, you might look at changes in the way players discuss these themes on social media as a proxy.
#### Poorly articulated outcomes
Poorly articulated outcomes can lead to indicators that don't accurately track progress or contribute to misunderstanding the impact. When defining outcomes in your results flow, put SMART goals to work!
## Responsibility
Who will collect the data or stories? This person is responsible for collecting data for reporting and analysis; it is not the person responsible for achieving the stated targets. Be as specific as possible  a name is best, but a job title, role, or department can work too. When it is time to collate and analyze your data, you need to know whom to go to. And they need to know the full scope of what they need to collect well before deploying tools like surveys.
## Frequency
How often will you collect the data: monthly, quarterly, semi-annually, or annually? Each indicator warrants a different cadence. It can take time for information to accumulate and for discernible changes to happen, particularly for those medium and long-term outcomes. But don't do it too infrequently, or you will miss opportunities to adapt or course-correct.
## Data Sources and Tool
#### Where will you get the data?
As noted earlier, data sources can be varied. Try to triangulate your sources, such as:
- **User playtesting/focus groups**: Feedback from users in structured sessions to understand user experience, game mechanics, and narrative effectiveness.
- **Anonymous user data**: Data gathered from user interactions with your games for quantitative insights into gameplay mechanics, user preferences, and behavioural patterns.
- **Community members**: Online communities related to your games (e.g., forums, Discord servers, social media platforms) tell you about game experience, character engagement, storylines, and community health and engagement.
- **Employees**: Experiences and observations of your wonderful team members highlight studio culture, development process, and diversity and inclusion initiatives.
- **Platforms**: Sales data, user reviews, and other metadata from Steam, Epic, Apple's App Store, Google Play, Switch, etc., shows you game performance and player engagement.
- **Existing databases**: Research databases, industry reports, and demographic data from industry associations such as the [ESA](https://theesa.ca), [Interactive Ontario](https://interactiveontario.com), and [DigiBC](https://www.digibc.org/cpages/home) give you context and comparison points for your indicators.
#### How will you collect the data?
The data collection method depends on the nature of the indicator you're tracking and the available data sources. Some examples include:
- **Monthly automated reports**: Some analytics platforms can generate regular reports providing detailed user activity, in-game events, and monetization statistics.
- **Surveys**: Online surveys can gather specific data directly from players or employees and can be designed to gather quantitative data (e.g., ratings) or qualitative data (e.g., open-ended responses).
- **Interviews**: Interviews with users, employees, or other stakeholders can provide rich, in-depth qualitative data.
- **Focus groups**: Gathering a group of users or other stakeholders for a discussion can provide diverse perspectives on a specific topic or issue.
- **Observation**: Behavioural data gathered from user interactions with your game or online communities can provide insights into play patterns, user engagement, and community health.
- **Research**: Secondary research (e.g., reviewing industry reports) can provide contextual information, trends, and benchmarks.
## Baseline and Target
A baseline and target are needed for each indicator to actually make use of your IMF.
Your baseline describes the situation at the _beginning_ (e.g. when you start a new project or start collecting data). For example, say you've just launched a new moon journey feature in your app. You start to collect data, and in one week, you have a baseline 10% of users have found and used that feature.
Once you have your baseline, you can set a target by stating a value or figure you aim for. Describe the desired situation if the change is realized, in terms of the indicator. It _must_ be realistic given your capacity and resources! Arriving at a doable target will take some trial and error.
Your target describes the desired situation if the expected change is realized, expressed in terms of the indicator. For example, "90% of users discover and use the moon journey feature in Q2 2021."
#### Setting targets and collecting data
Here are a few hot tips for setting your targets and collecting data!
1. Be kind to yourself: establish **realistic** targets and baselines. They set the direction for your work and form the basis for measuring success. Take into account factors like budget, available time, people-power, and tech resources. Overly ambitious goals will lead to frustration and setting the bar too low means you never reach your goals or make a real impact. (The opposite of what we're trying to do here!)
2. Consider the **cost** associated with collecting and reviewing data, the **time** it takes to gather it, the humans required for these tasks, and the software or technology needed to process and store the information.
3. Don't forget about **administrative tasks** like cleaning data to remove inaccuracies or inconsistencies, safely storing data to prevent loss and unauthorized access, and taking steps to protect data to ensure compliance. [Read up on federal and provincial/territorial privacy laws.](https://www.priv.gc.ca/en/privacy-topics/privacy-laws-in-canada/02_05_d_15/)
4. **Think strategically** about success and failure. Generally, success means meeting or exceeding your targets. Failure, on the other hand, could mean falling short of these targets _or_ running into negative impacts you didn't think of. But **failure is not a dead-end** it's an opportunity to learn, adapt, and improve your approach to impact measurement. It's part of your journey with us toward creating a more impactful, inclusive, and sustainable video game ecosystem in Canada. 😀
## Moving forward with your IMF
Creating an IMF is far from a "set-and-forget" thing; it's a living document with a complex interplay of elements that need to be kept top of mind, tracked, and updated regularly. Your operations will evolve as your studio matures, and so should your IMF. Regular reviews and revisions will keep it responsive and relevant to your goals.
Transparency is a huge opportunity once you've started measuring your impact. Don't just sweat over numbers behind closed doors **share your impact**. Report the good, the terrible, and the unexpected they're all part of your unique story and will resonate with those who care about what you're doing. Like us!
So, where are you at? Have some indicators you'd like some feedback on? [We'd love to hear about it](mailto:hello@weirdghosts.ca) and help you on your path to impact measurement.
#### Resources
- [Airtable IMF template](https://www.airtable.com/universe/expFQ8hvE8mapTVot/impact-measurement-framework?_gl=1%2A1gkbibu%2A_ga%2AMjAwMDc5MjY0Mi4xNjg4MTUwNjQw%2A_ga_HF9VV0C1X2%2AMTY4OTg3NDQ3My42LjEuMTY4OTg3NDU2Ni4wLjAuMA..)
- [Google Sheet template](https://docs.google.com/spreadsheets/d/1zHDdHi7EuYCVdHw_1LINMF5Ty9n1bu-XEQxn1Z5chnk/edit##gid=293015620)

View file

@ -0,0 +1,109 @@
---
title: Market Analysis
description: Market Analysis
category: strategy
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.226Z'
---
# Market Analysis
This _very basic_ guide will help you start **benchmarking** your competitors' games and collecting relevant data so you can do a competitive/market analysis for your game. This is how we do it for potential investees at Weird Ghosts!
## Step 1: Identify competitors
This might be the hardest part; only you can pick the most relevant games out of the vast ocean of storefronts and platforms. Consider both direct and indirect competitors those who make games very similar to yours and those competing for your audience (even if the game is quite different). Scour Steam, Epic, Switch, Xbox, Playstation, itch.io, Humble, GoG; ask around Gamma Space; bug your friends; and dig through showcases to come up with a list of 10-20 games that are similar to yours.
## Step 2: Analyze competitor games
Now, let's take a closer look and gather some data.
**Review gameplay:** Purchase or download as many of the games on your list as budget and time allows. Look at the mechanics, the story, the visuals, the sound, everything. Ask yourself: what makes each game stand out? Interesting mechanics? Aesthetics? A unique story or especially good narrative design? What do you like about each game, and what do you dislike?
**Read reviews:** Reviews are a goldmine. Keep an eye out for the things that come up repeatedly, both 👍 and 👎. Start with [Steam reviews](https://store.steampowered.com/reviews/), but also check out places like [Metacritic](https://www.metacritic.com/) and community Discords.
**How popular is it?** Use the [Steam Revenue Calculator](https://steam-revenue-calculator.com/) and [SteamDB](https://steamdb.info/) to understand how many copies they've sold and how much money they're making. Is the game doing as well as you thought it would, given its genre and how it looks and feels? Are some types of games doing better than others?
**What's the community like?** The size of the community and how active they are can tell you a lot about how well a game is doing. Look at their social media (TikTok, Instagram, and Twitter/X) — how many followers do they have, and how engaged are they? Do they have buzz going on in their official Discords or subreddits? A lively community usually means a solid player base, which means the game is probably doing pretty well.
**Marketing and PR:** How are they selling their game to the public? Are they active on social media or rely more on press releases and news articles? Are they working with influencers or streamers? And look at their trailers and other promotional materials. What's the vibe they're going for, and how does the public react?
## Step 3: Use tools to gather more data
Here are some recommended free or inexpensive tools that can help you gather data:
1. [Steam Hype Chart](https://plus.gamediscover.co/hype/) - This requires a Pro GameDiscoverCo account (well worth it for the data backend as well as the biweekly newsletter) and shows you the most anticipated upcoming games based on community engagement metrics.
2. [SteamDB](https://steamdb.info/) - This is a complete database of information about games on Steam. Shows player counts, historical data, graphs, and related information about any game on the platform.
3. [Steam Revenue Calculator](https://steam-revenue-calculator.com/) (Boxleiter Method) - This tool provides an estimate of a game's revenue on Steam based on the number of reviews it has received.
4. [VideoGameInsights](https://vginsights.com/) - This paid (and excellent) tool provides a wide range of data about games, including top games, trends, demographics, and more.
## Step 4: Create a competitor analysis spreadsheet
Organize the data you've collected into a spreadsheet ([template](https://docs.google.com/spreadsheets/d/1fxDBgs-AQl5SHRQwCoxwH53SY1Qjl_MhROwL7z0EpB0/edit#gid=1422843669)).
This will help you compare your competitors side-by-side and draw conclusions about how your game might fare. Here are the data points you'll need to collect:
| Field | Description |
|---|---|
|Title||
|Launch Date||
|Price|Full, non-sale price from Steam page|
|Total Reviews|Steam page|
|Sales Estimate|[GameDiscoverCo backend](https://gamediscover.co/)|
|Net Steam Revenue|[Steam Revenue Calculator - Boxleiter Method](https://steam-revenue-calculator.com/)|
|Wishlist rank|[GameDiscoverCo backend](https://gamediscover.co/)|
|Steam Followers|[SteamDB](https://steamdb.info/)|
|Twitter|Followers|
|TikTok|Followers|
|Reddit|Subreddit followers|
|Instagram|Followers|
|Switch|Yes/No|
|PS4/5|Yes/No|
|Xbox|Yes/No|
|Apple|Yes/No|
|Android|Yes/No|
|Net Other Console Revenue|Calculated automatically (adds 20% of net Steam revenue for each platform selected)|
|Total Revenue|Calculated automatically|
Fill in the relevant data for each competitor.
::alert{type="info"}
Here's a real example of a completed spreadsheet that we did for an investee: [**Cozy Games Market Analysis**](https://docs.google.com/spreadsheets/d/1mhf6Zae1CDPhx2WGfqLIc8PSiJ8Uzuo3rNYxE9Wugis/edit?usp=sharing)
::
## Step 5: Analyze data and draw conclusions
After you've gathered all the data, it's time to analyze it and draw conclusions.
**Identify successful game mechanics:** Pay attention to what mechanics make the top games in your genre successful. Could you incorporate these into your game, or improve on them?
**Look at pricing:** Are games in your genre generally free, low-cost, freemium, premium? What pricing model seems to generate the most revenue, and which aligns best with your game (and perhaps values)?
**Spot release trends:** Are there certain times of the year when games in your genre seem to launch more successfully? Are there any trends in how they launch (e.g. Early Access, full release, etc.)?
**Weigh the impact of community:** What tools and platforms do successful games use to connect with players and fans? What are those communities like? (Check out Victoria Tran's [Community Dev newsletter](https://www.victoriatran.com/newsletter) for great tips and analysis on this topic.)
**Determine the best marketing channels:** Which platforms are your competitors using to promote their games? Do they use influencers or rely more on press releases and news articles? Do they spread themselves out across all the social media sites or focus on one or two? What kind of content do they share, and how often? Identify the strategies that could work for you.
It's still _your_ game and you might decide to discard some or all of this intel. Don't feel like you have to do things the way others do just because they're successful. This is just one piece of the complex puzzle of marketing your game; only you know what feels right for you.
## Step 6: Keep it updated!
_That's all there is to it! lol_
Like all your studio and marketing tasks, this isn't a one-and-done thing. You'll want to keep your spreadsheet current (set a reminder to do a review every couple of months). And keep an eye out for new games, changes in pricing strategies, and trends around your genre's market.
If you have any suggestions about improving this guide or the template, please [get in touch with us](mailto:hello@weirdghosts.ca). Or better yet, hit that "Edit this page on GitHub" button at the bottom of the page.
- - -
**Resources**
- [GameDiscoverCo newsletter](https://gamediscover.co/)
- [How to Market a Game](https://howtomarketagame.com/)
**Tools**
- [Steam Hype Chart](https://plus.gamediscover.co/hype/) (requires Pro GameDiscoverCo account)
- [SteamDB](https://steamdb.info/)
- [Steam Revenue Calculator](https://steam-revenue-calculator.com/)
- [VideoGameInsights](https://vginsights.com/)

View file

@ -0,0 +1,210 @@
---
title: Pitching to Publishers
description: Pitching to Publishers
category: strategy
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.228Z'
---
# Pitching to Publishers
_Jennie's notes from Jason Della Rocca talk at Digital Alberta. These can be fleshed out and expanded on!_
## Mindset
Youre pitching an opportunity, not a problem. Pitching is a critical survival skill - theres no shame in getting out in the world and talking about yourself.
Think beyond publishers. Pitching is also to garner:
- Love/support from platform holders
- Favors from vendors
- Input from peers
Pitching is about getting people behind your vision. Think in terms of long-term relationship building - not every meeting is a win/lose.
## Before going
1. **Build a target list**
- Do research on past deals/genre tags supported by publisher
- Chase most important first
2. **Book meetings before the event**
- Chase via email, get intros, cold call
- Sign up for the matchmaking system
- Pro-tip: Schedule most important targets for day 2 - day 1 is for practice
- Avoid early morning - higher flake risk
- Pro-tip: Chase a published studio for an intro
3. **Prepare materials**
4. **Practice practice practice**
## Pitch materials
- Prep your meta materials for publishers to look at
- LinkedIn
- Website
- Social channels
- Prepare materials
- 1-pager
- Visual assets: video, screenshots, concept art
- Pitch deck
- Stable game build - absolutely essential
- Best result is request for pitch deck and build of the game
- Pro-tip: load everything to your laptop and phone for backup - dont rely on access to the internet
## Intro Cycle
Intro based on one-line summary and piece of art.
- Ideal if done via a mutual trusted connection
- Or “cold call” on LinkedIn/Twitter or meeting matchmaking system
Meeting request with one-pager
- Pro-tip: Include one-pager link in matchmaking system request
Likely agreement to meet
- May request extra information
- Dont send anything unless asked
Keep email exchange simple, focus on logistics
- Save game details for meeting
- Pro-tip: Update contact cell numbers
## 1-pager design
- 1 letter sized page, PDF
- Visually sharp like a movie poster
- Key data elements
- Genre, platforms, price-point
- Current production status, target release date
- Key features/USP
- Competition/market
- Studio logo, contact info
## Pitch formats
- Casual/at-the-bar
- Elevator
- “Performance” (e.g., GDC pitch, pocket gamer big indie pitch)
- Initial meeting
- Follow-up meeting
## Typical “1st Meeting Pitch” Elements
LESS IS MORE. Make it fit on 10 slides - target 5 minutes. No walls of text - keep it highly visual as support for your presentation.
1. **Awesome cover art/logo**
- **Goal**: Catch attention right from the start
- Establish brand vibe
![](/content/pitching-to-publishers/image1.png)
2. **Gameplay/story overview + art**
- **Goal**: Articulate core essence of the game succinctly
- Don't waste time on discussing combo mechanics for 20 minutes
![](/content/pitching-to-publishers/image2.png)
3. **Video clip**
- **Goal**: Show off how cool the game is and that it is (mostly) real
- Could be teaser, raw gameplay footage, mock gameplay
- 30-45 seconds
4. **USPs + art**
- Prove your game has unique/innovative elements, compelling
- Already thinking about how it will be marketed
- “Fun to play” or “indie style” are NOT USPs
![](/content/pitching-to-publishers/image3.png)
5. **Traction**
- **Goal**: Prove that others think you are cool or worthy
- Social media likes and views
- Festival selections/showcases
- Discord size
- Press coverage
- Special deals, relationships, partners, advisors
![](/content/pitching-to-publishers/image4.png)
6. **Business model + Competitive analysis**
- **Goal**: Demonstrate there is a market for your game
- Include: pricing, platforms, genre tags
- Skip sales forecasts and focus on finding good comparables
- Ideally games released in the last 12 months
![](/content/pitching-to-publishers/image5.png)
7. **Production timeline**
- **Goal:** Help publisher understand the state of the game and how much work is left until launch
- Use “sausage” timeline visual
- Include key production milestones past/future, reveal, release, DLC dates, events or big marketing beat dates
- Assumes you have budget and production schedule!!
![](/content/pitching-to-publishers/image6.png)
8. **Team, pedigree, awards**
- **Goal**: Convince them you are the team to make this amazing game
- Can include production partners
- Past notable studios/projects
![Your team information](/content/pitching-to-publishers/image8.png)
9. **Ask**
- **Goal:** Clearly ask what you need and expect from the publisher
- Can cover stuff like:
- Funding requirements and broad use of funds
- Role/functional needs (ie, PR, trailer, localization, porting, etc)
- Product/genre expertise
- Specific geographical or platform needs
![Your ask](/content/pitching-to-publishers/image9.png)
10. **Contact/socials info, more awesome art**
## Practice, practice, practice
### During an event
1. **Use 1hr meeting blocks to allow for buffer**
- Be 2 people in each meeting (one talker, one note-taker)
- Pro-tip: Mark actual local time in the calendar title
2. **Meeting zones**
- Biz lounge
- Expo/booths
- Other chill areas like hotel lobby - scout in advance
3. **Daily debriefing and tweaking**
- After each pitch, assess how it went and update your deck
4. **Meeting flow**
- Typically 30 minutes
- 3 min. - small talk and biz cards
- 7 min. - Get publisher talking about themselves
- Pro-tip: Get them talking first so you can modulate
- Ask open ended questions
- 5min. - Run through deck
- 5 min. - offer to play build (theyll prob decline)
- **10 min. - Q&A/discussion and next steps**
5. **On-site chasing**
- COVID impacts to keep in mind
- Parties and networking events
- Ask for on-the-spot intros via other devs
6. **Goal of the meeting**
- Get past the “shit-filter”
- Assess compatibility
- Timing, funding size, roles
- Setup next meeting, post event
- Have clear follow-up/action items
- Collect market intelligence
- Use notes! What are publishers focused on?
7. **Post-show follow-up**
- Debrief and update targets spreadsheet
- Pitch postmortem (what went right/wrong, to improve)
- Follow-ups
- Follow-up emails per action items
- Add everyone on LinkedIn
- Nags
- Max 2 nags after call, 1-2 weeks apart
- Afterwards, only ping based on meaningful progress
![Post-show follow-up](/content/pitching-to-publishers/image10.png)

View file

@ -0,0 +1,155 @@
---
title: Process Development
description: ''
category: studio-development
tags: []
accessLevel: member
author: Weird Ghosts
publishedAt: '2025-11-10T10:52:42.624Z'
---
# Collaboration, Process Development and Tools
## Overview
We started by understanding our [goals and values](/studio-development/collectivism/actionable-values), which form the foundation for everything we do in developing a collective-minded studio. We then explored the [development and structure of the studio](/studio-development/collectivism/co-op-structure) and how collectivism functions within that structure. We also talked about [decision-making](https://learn.weirdghosts.ca/studio-development/collectivism/decision-making) and how it informs our processes. In this article, we'll be focusing on **collaboration**, **process development**, and **tools**.
This isn't about how to use specific tools, though we will take a peek at some Miro flows and UI. More importantly, we'll be discussing why we develop certain processes and how they benefit the collective.
## Developing Collaborative Processes
Processes provide **visibility into accountability**. When we document our processes, everyone understands why things are the way they are, and they can adapt to the needs of those who are responsible. This means that there's no one-size-fits-all approach to processes, and we should review them regularly as requirements and roles evolve. Since your studio will likely change with members coming and going, it's worth iterating on your processes to ensure they remain effective.
In a collective, the processes you adopt are a **reflection of your studio structure**. The design of your processes is an opportunity to practice inclusion and care. This is something that people often overlook when developing their processes for the first time. Think about your values: Who can access your processes, and how can you make them accessible to as many people as possible? Of course, some things are just what they are. For example, if your studio is focused on audio design, being able to hear the sound is critical. There's only so much you can do for people who can't hear. However, you can address accessibility needs by accommodating different learning styles and providing various ways to access processes and information (such as text, video, mind maps, etc.). By recording and using processes with regularity, you're ensuring continuity in the operations of your studio, even in the face of change. Things will inevitably change, so it's important to avoid relying on just one person or system. Have a backup plan.
## Evaluating the Role of Productivity
In traditional companies, productivity and efficiency are the most important aspects of a good process. But these aren't the only factors that should be prioritized, especially if you are trying to do things a bit differently from the norm. While it's useful for members to feel empowered to streamline their work and eliminate unnecessary steps or tasks, try to examine what this emphasis on productivity means in the context of our capitalist society. We need to ensure that our focus on efficiency doesn't result in overworking or burnout, for example. Instead, we should use tools and processes to help us **stay organized** and **communicate better** so that we can focus on the work that really matters.
To illustrate this point, let's take a look at a typical co-op structure and the various roles and responsibilities involved. Members are responsible for voting on co-op decisions, while directors facilitate governance development and may handle government filings. Management is typically responsible for project management and reporting, while workers create and develop asset pipelines. By understanding these roles and responsibilities, we can work together more effectively and ensure that everyone's contributions are valued.
## Reusability of Processes
What's interesting is that creating processes can have multiple purposes and roles. For instance, a process for meetings can be used for any type of meeting within the co-op structure, from standups to the annual general meeting (AGM). It could be applied to one-on-one meetings, committee formations, and collaborations. The process of committee formation can be compared to working groups or node formation. Once you create a process, it can be reused for any committee or ad hoc group in your co-op.
When it comes to reporting, get specific. Describe the purpose of channels and how you handle task assignment, handoff, asset storing, and more. Asset storing can include 3D models, textures, sound libraries, co-op reference documents, financial documents, and other things. Although the specifics of how we store and name these assets may differ, the process of uploading them, making backups, and notifying everyone of the changes can remain consistent throughout the entire co-op.
## Example Task Framework
When developing and analyzing processes, it can be helpful to think of them within a framework. One such framework that one of the Gamma Space members has been using for over a decade is what they call the core loop of Meet, Make, and Manage. Each of these functions is essential, and everyone performs them at some point.
- **Meet** is where you plan, solve problems, and document decisions.
- **Make** involves building, testing, and relaying what came out of the Meet stage.
- **Manage** is where you report, resolve discrepancies, and update communication as necessary.
This framework can provide a useful starting point for analyzing your processes, but it's just one example.
## Implementation Considerations
### Understanding the Purpose and Goals
Identifying when to implement a process involves asking a few essential questions.
First, we need to understand _why_ we are creating this process and _what_ we want to achieve through it. These are two different questions that require separate considerations as they may have variations or multiple parts to them.
Second, we need to determine how to carry out the process and who will be affected by it. This includes considering the scope of the process and the frequency with which it will be used. You'll need to understand these factors to determine how complex or rigid the process should be. By addressing these questions, you can develop a clear and effective process that meets your needs and achieves the desired outcome.
### Responsibility and Specialization
Here are some factors to consider when applying a process:
- **Responsibility**: Who's leading the process? Is it a stewardship role or something like IT support, for example?
- **Intensity**: Is it very focused and on-demand or more casual and requiring less attention?
- **Frequency**: Is it regularly scheduled or done on an as-needed basis?
- **Degree of specialization required**: Do you need someone who is highly skilled or is minimal training sufficient?
### Process Implementation and Adaptability
Well-planned and considered processes can make complex tasks less daunting. For instance, if you're working with a governance committee, you don't need to know _everything_ about governance. Instead, you can focus on tasks such as hosting meetings and making sure you have a representative from every node. The governance committee can bring everyone together and facilitate conversations around fundamental changes to decision-making, working with subcontractors or contractors, and other relevant topics.
The key is to have a question or goal in mind and facilitate the conversation around it. By allowing people to contribute to the agenda ahead of time, you can ensure that everyone's voice is heard and the meeting is productive.
Thoughtful processes can mitigate many issues. This is particularly important for small teams. Context switching can be a major headache, especially for small teams. For example, switching between filing a CRA form and designing a level can be pretty challenging. There's no magical secret to make this easier, but having a well-defined and thoughtful process in place can help people go through the steps more efficiently. It may be helpful to allocate specific time for this.
### Quantifying Processes in Small Teams
It's essential to quantify these processes, even in small teams, to attach a value to them. This way, we can better understand the value flow and granularity and get a complete picture of what's going on. This helps us address any issues that team members may feel uncomfortable about.
If it's become untenable, maybe because you're too small, what are you going to do about it? As you are aligned, respect shared processes and values you'll work through it and figure it out.
But what _doesn't_ work is working individually and then coming together and expecting it all to magically coalesce because you all get along on pizza night. Yes, you probably see your team members as friends, which is admirable. But resentment can happen when a context switch becomes an expected, almost semi-permanent thing. And that's why it is helpful to regularly review your processes, and not rely on good vibes.
### Game Dev to Non-Game Dev Work Ratios
Finally, consider game dev work to nongame dev work ratios. For example, it might sound frustrating to spend three weeks writing a proposal without touching your level design tasks. However, as a member of a team, you have ownership and responsibility over the project as a whole. Everyone on the team must share in the non-game development tasks, or knowledge about how to complete them must be shared amongst the team. So, how can we do this? When do we get to make our game?!
### Documentation and Knowledge Sharing
A great first step is to write down the process you followed, even if you don't have the answer yet. This way, you can share it with the group and see if anyone else can help. If you're struggling with something specific, like creating a budget in a spreadsheet, that's okay. There may be others who are willing to help with everything else, leaving you to focus on your specialized skill. Having this framework will help you have clear conversations about how best to approach the task.
## Tools for Effective Collaboration
Tools help facilitate process. They are not a replacement for process. Your desired process should always be considered as you select a tool. A common issue, particularly for small teams, is the lack of a dedicated project manager. If you don't have a project manager, you're probably going to look into a tool of some sort. Some try to ease into it and give you a starter template or link to a production methodology. But the truth is it's not the same as having a skilled person there to help you. This is why your process should inform your tools.
Some tools have features that may help inform the process you choose and let you learn something from it  but it shouldn't dictate it. Just because JIRA is set up perfectly for doing scrums and Agile development, doesn't mean that your team has to do Agile development. In fact, for a lot of small teams, Agile development is not particularly helpful.
Some tools have implications when they are weighed against your values. This applies even when you are considering tools that are not specifically related to processes but rather used for creation. We have previously discussed this in the context of deciding between Godot and Unity. Game Maker may also appear appealing now, but their recent move to a free model could be subject to change at any point. You should also consider how open-source tools and reliance on big tech companies play into your decision-making process.
Slack is a big tech platform, and although there are non-big tech alternatives available, they may not offer all the same functionality as Slack. Similarly, Discord may not be suitable for every community. Regardless of which platform you choose, you are still at the mercy of their decisions regarding free plans and pricing for non-profit organizations. Make contingency plans and regularly explore alternatives.
## Miro UI Tips
_to be added_
It's worth thinking about what you're trying to accomplish in your process, then finding tools that allow that.
One Gamma Space member says they were initially put off by Miro, as a person used to storing documentation and ideation as plain-text files. But when the pandemic hit, being inside a "page" with other people was comforting and helped him feel connected when our space had closed. And now the tool is central to our processes. So, give yourself the chance to see processes differently than you usually do.
Even if you are working with your team in person, a virtual whiteboard tool can still be helpful. Not to mention, it helps address accessibility needs for folks who can't come in to the office.
## Project Management is a Flow
Regardless of the tool you're using, you'll need to establish a workflow process. This applies to your virtual whiteboard, where you might plot marketing and development ideas, as well as your project management tools, covering everything from assignments to task completion (and any other tools!).
The assignment of tasks may seem straightforward, but it raises questions, especially if your team doesn't have project manager. Should the task-assignment role rotate based on the current sprint or work unit? Or should it fall to the person coming up with the idea? In some cases, it's someone other than the person executing the task, which streamlines the process for review and accountability.
The execution of tasks often leads to ambiguity. A common scenario involves someone marking a task as done without thorough completion or oversight. This raises the question of who reviews these tasks. Trust and repeatable review processes are critical here. In our workflow, task completion and review expectations are clearly set from the start, ensuring everyone understands their roles and responsibilities.
## Communication and Reporting Dynamics
Balancing conversation and reporting is another issue. In platforms like Asana, comments can either facilitate discussions or become a space for making decisions. In our case, conversations about tasks happen in Slack channels related to the project, while the decisions and actionable steps are recorded as comments in the Asana task.
Integrating task management tools like Asana into communication platforms like Slack can be challenging but beneficial. You need to be clear about where conversations and decisions take place. For example, any decision made during a discussion in Slack can be added to the relevant task in Asana for clarity and documentation.
## Example Workflow
Take a simple workflow:
1. The project lead assigns a task.
2. The team member then devises a strategy for execution.
3. If needed, support is brought in.
4. Once the task is complete, the lead reviews and marks it as done.
Visualizing this workflow on a Kanban board, such as in Asana or Trello, helps track the stages of a task whether it's due, in progress, ready for review, or completed. Again, the choice of tool is totally up to you!
In our approach, before marking a task as complete, the lead and team discuss the tasks and necessary communication channels. This ensures everyone understands the workflow. The lead then reports on the outcomes according to the set schedule. This is our specific structure, but you can adapt it to fit your own needs. Carefully consider how you incorporate these things into your structure don't just insert a tool or process all willy-nilly!
## Conclusion
So, to summarize, our process is iterative and recursive. It begins with defining our goals and values, followed by studio development and decision-making. We then develop our collaboration processes. These collaboration processes can influence and improve the initial stages as we revisit them. This means that as we learn to work more effectively together, we can refine our studio's foundational elements, like goals and values. Remember, our goals and values are not fixed; they need to be continually refined. This commitment to improvement helps us build a strong collective, enabling us to make diverse decisions and establish structures that truly challenge industry norms.
---
### Q&A
**Q:** In a small team of three to four members where there are no designated roles like a producer or a team lead, how are tasks typically reviewed, created, and assigned? Can you provide an example of this process?
**A:** First: Recognize the importance of discussing rules, responsibilities, and structure with everyone on the team. At Gamma Space, it's crucial for someone to responsibly steward a project, though this role doesn't have to be fixed and can rotate. We've implemented a concept of "on and off ramps," allowing changes in who leads project management.
Before a task is added to a tool like Asana, we define its scope and timeline, identifying who is responsible and when they can transition out. For example, a person might lead a task with high intensity for two months, after which they can step back, and someone else can take over. This process is planned and understood by everyone, enabling flexibility and learning opportunities, especially for those with varying levels of experience.
It's easy to see how important an approach like this is in a cooperative environment where everyone shares ownership, responsibility, and accountability for the organization's health. It's not about hierarchy but about creating a system that's adaptable and conducive to learning. Not all co-ops operate this way some prefer more rigid structures. However, each co-op must choose a method that aligns with its values and impact goals.
Regarding task management in Asana, we could implement a system where everyone pairs up to review at least one other person's tasks. This ensures collective oversight, but we use our judgment to avoid redundancy, like reviewing every step of a repetitive task. This is where discernment comes into play. It involves not just intelligence or experience but the ability to assess whether a process is efficient and if there might be a better approach.
_This content was developed by [Gamma Space](https://gammaspace.ca) for a 2023 Baby Ghosts cohort presentation. We have summarized and adapted it here._

View file

@ -0,0 +1,128 @@
---
title: Publisher Contract Review
description: ''
category: strategy
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.229Z'
---
# Whitethorn Games Contract Review
WhiteThorn made their [agreement](https://docs.google.com/document/d/e/2PACX-1vQYB4MfO44m7KRK73lMCis52XvmATIb9sy3NwoIRI4d50SyXPO4v0kg3PDxXMU2Cjjw-L5D-gWKK9dR/pub) public in response to Raw Fury doing the same. They are an American indie publisher of cozy games.
## Making the game
### Typical Indie Contract:
- Publisher finances development.
- You submit milestones and get paid as milestones are approved by Publisher.
### Whitethorn:
- Fixed monthly payments for 21 months.
- No clear date for gold master or publishing the game.
- No milestones or approvals, but provide access to builds every two weeks.
- Developer has creative control, but Whitethorn has disability/accessibility input rights.
### Pros:
- Very flexible for Developer.
- Money not tied to publisher approval of milestones.
### Cons:
- Missing a deadline by 10 days allows contract termination.
- No post-launch milestone revenue = cashflow issues.
### Making it more Indie-friendly:
- Rework penalties for late delivery (see termination section).
- Address post-launch cashflow:
- Extend monthly payments past launch, or
- Negotiate 80/20 or 90/10 pre-recoup rev share, or
- Ensure that studio has sufficient cash on hand.
## Marketing the game
Typical deals are vague about marketing obligations and whether the publisher must publish the game. WhiteThorn provides marketing budget, by consensus. No guaranteed publishing date; no mention of pricing, discounting etc. Vague mention of merchandising. Very vague about merchandising and porting.
### Suggestions:
- Ask for a marketing plan and attach to the contract.
- Add clauses that guarantees publishing.
## Revenue calculation and sharing
### Typically:
- Publisher recoups development costs, marketing.
- Rev share during recoup is between 100/0 to 80/20.
- Post-recoupment split is around 50/50, depending on publisher investment level.
- Rev share may shift towards developer over time.
- Payments are made monthly or quarterly.
### WhiteThorn:
- Publisher recoups 100% of development expenses, 30% of PC/console marketing, 100% of mobile marketing.
- Pre-recoupment rev share is 100/0.
- Post-recoupment rev share is undefined.
- Merchandising revenue is either 100/0 for Developer, or 50/50 if sold via Publisher. No one does less than 50/50 after recoup.
- Porting costs are non-recoupable.
- Monthly payments.
- Good developer audit rights.
## Intellectual property ownership
Developer retains ownership of IP. Publisher has exclusive licence (transfer of almost all IP rights to the publisher) over platforms/markets covered by contract. What you get in return is royalties. Rights of first refusal/first offer on sequels and expansions.
### Suggestions:
- Negotiate how long until you get IP back - it should be tied to publishing timeline.
- Net revenue may be calculated differently by an accountant and a lawyer. Be clear.
## How easy is it to get out of this deal?
One successful game gives you a lot of bargaining power. (As does having multiple publishing deal options)
## Termination Rights and Obligations
### Typical Indie Deal:
- Roughly 5 year duration.
- Termination if one side breaches the contract.
- Termination on mutual agreement.
- Publisher can terminate before launch without needing a reason, but pays a financial penalty (typically 1-2 milestone payments) and has no ongoing rights in the game if it does so.
### Whitethorn:
- Duration is essentially 2 years from first publication on any platform, but duration is somewhat unclear.
- Both Publisher and Developer can terminate at any time on 60 day notice.
- No penalty for Publisher doing so.
- If Developer does so, continued payment of rev share for 24 months.
- Developer or Publisher can terminate if the other side breaches and that breach continues for more than 10 days.
### Making the contract more indie-friendly:
- Clarify the duration of the contract.
- Extend the 10-day notice period to 30 days for termination for breach.
- Clarify the penalty for termination without cause by both Publisher and Developer.
- Add developer termination rights for failure to publish.
- Specify what happens on termination in greater detail, especially ports.
## Risk allocation
### Typical Indie Deal:
- You're on the hook for allegations of IP infringement, or other problems with the game.
- This is a low-risk, high-impact clause
- Patent trolling is no longer common
- Get insurance! Especially if you have more than the current IP
### Whitethorn:
- No promises regarding bugs and viruses, IP infringement warranties are really generous. Negotiate a qualifier.
### Pros:
- Very reasonable risk allocation for the Developer.
### Cons:
- None, really.
### Making the contract more Indie-friendly:
- These are all low-risk, high-impact clauses.
- But overall, take these as-is.
## Final thoughts
Raw Fury's contract in a word: Sneaky
Whitethorn's contract in a word: Sloppy
Bottom line: Whitethorn is still the most indie-friendly contract he has seen to date. Whether compared to Raw Fury or anyone else. Exhausted supply of public contracts - Raw Fury took a lot of flak online for theirs and no one else is really coming forward. Montreal indie contract idea.

View file

@ -0,0 +1,242 @@
---
title: Results Flow
description: A step-by-step guide to creating a results flow for your indie game studio.
category: impact
tags: []
accessLevel: member
author: Weird Ghosts
publishedAt: '2025-11-10T10:52:42.626Z'
---
## Creating a results flow for an indie game studio
Capitalism tells us only financial returns  the bigger, the better!  are important. But it doesn't have to be this way. Broadening our understanding of _what value means_ can create more sustainable ways of working (and funding that work.)
Capitalistic returns almost always come at a great human and social cost. Extracting as much value as possible necessitates poor pay and working conditions; it keeps value from flowing to workers and really anyone who isn't at the top.
We don't just make games and print money. We work with humans who have needs and desires. We make cultural products that live on in players' imaginations and alter their perspectives; our ideas and work affect individuals and communities in ways we both intend and can't anticipate.
**So how can we account for and value positive social impact in our studio operations?**
In our blog post [A Brief Intro to Making Your Indie Game Studio Impactful](https://weirdghosts.ca/blog/a-brief-intro-to-making-your-indie-game-studio-impactful/), we explored how you can start thinking about what makes an impactful game studio. (If you haven't read it, take a moment now to get a grasp on the concept of social impact strategy for indies it's not common in our industry!)
We also talked about imagining your _dream world_, and how to begin thinking about the social impact of what you do:
> To start your impact journey, **you need to describe your dream-world**. What does the planet look like if you are successful in achieving the change you want?
> Once you've defined your dream world, you need a strategy for making it a reality. Your strategy will align your actions and intended impact within the constraints of the resources you actually have.
## What's a results flow?
So, let's take a closer look at a tool for planning and measuring your studio's impact: The **results flow**, also known as (or similar to) a theory of change, logic model, or results chain. This tool will help you visualize the chronological (and logical) sequence of events from activities to outcomes that lead to your ultimate desired impact. It's a visual roadmap that illustrates what you need to do and what you expect to achieve.
The cool thing about a results flow is that it can incorporate all of your studio's goals and activities, not just those oriented toward social impact. It also:
We'll guide you through the process of developing your own results flow. First, we'll clarify some key concepts, then walk you through crafting your **intended impact statement**, drafting an **ultimate outcome statement**, and creating your **results flow** through backward mapping. We'll also get into how to inventory your activities, refine your diagram, and evaluate its realism and logic.
This guide, aimed at folks just embarking on their impact journey, will give you some practical advice and clear steps to help you on your way. We hope it will lead you to think deeply about the impact of your games and how your studio operates.
So, let's start developing a results flow for your studio!
### Understanding key concepts
First, let's clarify some key terms we'll use throughout this guide. These concepts form the backbone of your social impact strategy and will help you articulate and measure your studio's impact.
- **Activities**: The specific actions, initiatives, core tasks, and projects that your studio engages in.
- **Outputs**: These are the direct products of your activities. They are the tangible and intangible goods or services produced from your work (e.g., a published game, a completed client project, or a social media campaign).
- **Inputs**: These are the resources you need to carry out your activities (e.g., funding, collaborators, audience research, computers).
- **Intended impact**: This is the _change you will be accountable for_. It's a hypothesis about what will lead to your desired ultimate outcome. Your intended impact statement is not about your activities, projects, or strategy but rather the change you aim to make. It's about defining success for your studio and committing to your activities and outputs. It should clearly describe **what** you will achieve, **who** will benefit, and by **when**.
- **Ultimate outcome statement**: This describes _how the world looks if you are successful_. It's a vision of your dream world — how it would be if you achieved the desired change. You should word your ultimate outcome statement in the present tense and not worry about the scope or scale. What feels right — is right! It doesn't have to feel achievable or realistic right now.
- **Results flow**: Also known as a theory of change or results chain, a results flow is a _visual map of the sequence of events_ from activities to outcomes that lead to your ultimate outcome. It illustrates _what you need to do_ and _what you expect to achieve_ along the way.
Understanding these concepts is the first step in developing a results flow for your studio. In this article, we'll get into the details of how these elements relate and how you can use them to plan and implement your studio's social impact strategy.
## Crafting your intended impact statement
Your intended impact statement is the starting place for developing your results flow and informs your entire social impact strategy. It's not about activities, projects, or strategies. It's about _defining success_ for your studio. It's about the _change_ you will make. And it should clearly describe **what** you will achieve, **who** benefits, and by **when**.
You need to understand your dream world to start crafting your intended impact statement. What do things look like if you are successful? Now get specific: What is the timeline, who is impacted, and what will be achieved? Being clear about when, who, and what is critical because it embeds the potential for _accountability_ into your dream world and makes it possible to create a workback plan and determine what resources are needed to get there.
Consider:
1. **What change will you make?** This is about the specific outcomes you're aiming for. What change do you want to see in the world due to your studio's work?
2. **Who benefits?** Consider your target population, identity, and geography. Who are the people or communities that will benefit from the change you're aiming to make?
3. **By when?** What is the timeframe for achieving this impact? Aim for 2-7 years. This helps to keep your goals realistic and achievable.
For example:
> By 2026, our studio will cultivate acceptance and understanding of Gen Z LGBTQIA+ perspectives among at least 40,000 players through our games that feature diverse characters and inclusive narratives.
Remember, your intended impact statement is not about the activities you're doing. It's about the specific results of your activities. It's how you move from _what we do_ to _what we contribute_. This clarity will push you to maintain focus and sets the stage for allowing your team to be held accountable.
Take some time to draft your intended impact statement. Don't worry about perfecting it at this stage. Just try to get these three elements defined. Review and refine your draft statement once you're happy with it. Share this process with your team and integrate their feedback.
Note the difference between a mission or vision statement and an intended impact statement. A mission or vision statement is broad and idealistic, focusing on what the studio is _doing_ rather than the _outcome_ of its work. An intended impact statement, on the other hand, is specific and measurable, focusing on the change you will make, who benefits, and by when.
## Drafting an ultimate outcome statement
When you're happy with your intended impact statement, it's time to draft your _ultimate outcome statement_. This statement is the full, boundless vision of your dream world how it would be if you successfully achieved the change you want. It's about imagining the broadest impact of your work and how it contributes to the world you want to see.
Here's how to approach drafting your statement:
1. **Imagine your dream world**: Don't limit yourself by doubting whether it's possible or wondering where you'll get the resources focus on what feels ideal to you. This is your chance to dream big and articulate the world you want to help create!
2. **Use present tense**: This helps to make it more tangible and real as if it's already happening. It makes it easier to understand whether or not you've achieved this goal later down the line.
3. **Keep it pithy**: It doesn't need to be long it's often more powerful when short and precise. Try distilling your vision to its essence, capturing the heart of your goals as a studio.
Here's an example:
> LGBTQIA+ identities are understood and accepted in games, mirroring a society that celebrates diversity and inclusion.
While your intended impact statement is about the specific, measurable change you're committing to make, your ultimate outcome statement is about the broader impact of your work and the world you want to see.
Take your time with this step. Try to capture your vision as clearly as you can. Once you've drafted your statement, work on honing it with your team until it feels right. It could take days or weeks to arrive at something resonant.
#### Inventorying your activities
Inventorying your activities is next don't worry, we're getting close to actually creating your results flow! This step involves identifying your studio's different core activities and understanding the outputs associated with each activity.
###### Identify your activities
First: List all the different activities that your studio does or offers. Think game development, porting services, writing articles, education and outreach, researching, or developing relationships with communities. Think beyond game production — what other types of tasks and projects do you or want to do?
Once you have a complete list, whittle it down to your primary 3-5 activities. (Don't stop doing the rest. We're just identifying which activities are _central_ to your studio's operations and impact.) Ask yourself: Can some activities be combined? Are there activities that are essentially part of the same process or aim at the same outcomes?
###### Understand the outputs
Label the associated outputs for each core activity you've identified. For example, if one of your activities is game development, the output is a published game. The output could be a completed client project if you're offering porting services. If you're writing articles, the output is a published article.
Your outputs are the tangible results of your activities that lead directly to outcomes. They are the _evidence of your work_ and the first step towards making your intended impact.
The goal of inventorying your activities is not just to have a list of what you do but to lay the groundwork for mapping these activities to your intended ultimate outcome. This understanding will help you refine your results flow and ensure that your actions will lead to your desired outcomes.
## Examples
Here's an example of a results flow from Weird Ghosts to help you visualize what we're aiming for:
![World of Weird - Results Flow](/content/results-flow/weird_ghosts_results_flow.jpg)
To illustrate that your diagram can be formatted differently, here is [Mozilla's Theory of Change](https://foundation.mozilla.org/en/insights/trustworthy-ai-whitepaper/path-forward/introduction-theory-change/):
![](</content/results-flow/MoFo_AI_Theory_of_Change_(ToC)__Landscape_Design.jpg>)
[Canada Learning Code](https://www.canadalearningcode.ca/theory-of-change/)s:
![Canada Learning Code TOC](/content/results-flow/clc_theory-change-2020_EN.png)
And [Furniture Bank](https://www.furniturebank.org/charity-intelligence/)s more illustrative diagram:
![](https://www.furniturebank.org/wp-content/uploads/TOC-FB-2023-2048x1152.png)
## Backward mapping: Creating your results flow
Backward mapping is a strategic planning process that starts with your ultimate outcome and works back to connect it to the activities you've identified in the previous step. This approach ensures that everything you do is aligned with your ultimate goal.
Here's how to create your results flow through backward mapping:
#### Start with your ultimate outcome
**Begin by stating your ultimate outcome.** Place it at the top of your workspace in a visual tool like [Miro](https://miro.com/). In addition to the above, another example is Weird Ghosts' ultimate outcome: "All marginalized game creators and studio founders in Canada have equitable access to a sustainable funding system and the resources they need to achieve their goals." (Psst… if you use Miro, copy [this board](https://miro.com/app/board/uXjVM4S_rag=/?share_link_id=763577396820) to get started really fast!)
![](/content/results-flow/creating-step-1.jpg)
#### Identify your activities
Next, **place your core activities at the bottom** of your workspace. You identified 3-5 of these in the previous step. An example: One of Weird Ghosts' core activities is offering a peer-led community-based training program. Another example could be "Developing games that feature LGBTQIA+ characters and narratives." In the diagram below, we've also created labels for each pillar.
![](/content/results-flow/creating-step-2.jpg)
#### Brainstorm long-, medium-, and short-term outcomes
For each activity, brainstorm the outcomes you expect to see in the short, medium, and long term. These outcomes should be a _direct result of your activities_ and point toward your ultimate outcome.
- **Short-term outcomes** are the immediate effects of your activities _changes in skills, knowledge, awareness, interests, and motivation_. For example, a short-term outcome of Weird Ghosts'" Community" activity is that creators feel an increased sense of community. In the case of developing games that feature LGBTQIA+ characters and narratives, a short-term outcome could be "Players gain exposure to diverse characters and narratives."
- **Medium-term outcomes** are the _changes in action, behaviour, practice, and attitude_ that result from the short-term outcomes. For Weird Ghosts, a medium-term outcome is that creators reinvest in the community. A medium-term outcome for the game development activity might be "Players develop empathy and understanding towards LGBTQIA+ identities."
- **Long-term outcomes** are the _changes in state or condition_ that result from the medium-term outcomes. A long-term outcome for Weird Ghosts is that creators feel a sense of belonging to a community they can engage with, support, and draw from. In the case of the game development activity, a long-term outcome could be "Players advocate for LGBTQIA+ rights and inclusion."
In your visual workspace, draw three columns or pillars below your ultimate outcome for these long-term, medium-term, and short-term outcomes. Place the long-term outcomes closest to the ultimate outcome and the short-term outcomes at the bottom.
![](/content/results-flow/creating-step-3.jpg)
#### Map outcomes to activities
Now, draw lines to connect your activities to your short-, medium- and long-term outcomes and those to your ultimate outcome. Each line represents a step in your results flow, showing how each activity and outcome contributes to your ultimate outcome.
![](/content/results-flow/creating-step-4.jpg)
This process will require some iteration as you make connections between your activities and outcomes and refine your outcomes to be as clear (hint: and as _measurable_) as possible. It's okay if it's not perfect on the first try this is a living document. We just updated Weird Ghosts' last month!
By the end of this process, you should have a clear visual representation of your results flow, showing how your activities lead to your ultimate outcome. This will be a critical tool for planning, implementing, and evaluating your studio's impact. You can read more about that in our article [Developing Your Impact Measurement Framework](/impact-tools/imf)
## Refining your results flow
Once you've drafted your results flow (_woo!_ 🙌), you can further refine it. Let's talk about it.
#### Identifying necessary resources
To pursue your outcomes, you'll need to ensure you have the right resources in place. Think funding, hiring artists, audience data, and the right graphics cards for your team. Reflect on each activity and outcome in your results flow and ask yourself: Do we have what we need to make this happen? If not, what's missing, and how can we secure it?
#### Considering activities to start or stop
You might realize that there are activities you're currently doing that don't contribute to your ultimate outcome. Or, you might identify new activities that could help you achieve your desired outcomes. This is a time for honest evaluation and (potentially) tough conversations. Don't be afraid to stop activities that aren't serving your goals or start new ones that will. For example, you might decide to stop certain marketing activities that aren't reaching your target audience or to start a new partnership with a community organization that offers support your team can't alone. (Like our partnership with [Gamma Space](https://www.gammaspace.ca) to deliver the [Baby Ghosts](https://weirdghosts.ca/baby-ghosts) program).
#### Prioritizing what is necessary now
While planning for the long term, figuring out what to do _now_ is also crucial. You don't need to implement every single column/pillar in your results flow right away. Instead, prioritize the activities and outcomes that are _most urgent or doable_ in the short term. This will help you conserve and build up energy and resources, putting you in a better position to tackle your long-term goals.
## Reflecting on your results flow
You've refined your results flow now it's time to evaluate it. You'll check the realism and logic of your diagram and identify the outcomes you will hold yourself accountable for achieving.
#### Checking the realism and logic
Start by considering the feasibility of your plan. Ask yourself: Are the proposed activities likely to lead to the expected outputs? Are the connections between activities, outputs, and outcomes logical and realistic? Will we be able to secure the resources we need to pursue these outcomes?
For example, if one of your activities is "Developing games that feature LGBTQIA+ characters and narratives," and a short-term outcome is "Players gain exposure to diverse characters and narratives," consider whether this activity will realistically lead to this outcome. Will your target audience likely play your games and be exposed to diverse narratives? What will you do to engage this audience directly?
Also, consider the logic of your outcomes. Do your short-term outcomes _logically_ lead to your medium-term outcomes, and do those logically lead to your long-term outcomes? For example, does gaining exposure to diverse narratives logically lead to developing empathy and understanding (a medium-term outcome), and does that logically lead to advocating for LGBTQIA+ rights and inclusion (a long-term outcome)? Consider the nuances that need to be present in your work to lead to each outcome.
#### Identifying outcomes you will hold yourself accountable for achieving
Next, decide which outcomes on your results chain you will commit to achieving and, therefore [_measuring_](/impact-tools/imf). This is about setting clear commitments and holding yourself accountable.
For example, you might decide to hold yourself accountable for the short-term outcome of "Players gain exposure to diverse characters and narratives." This means you would need to find ways to measure this outcome, such as through player surveys, feedback, discussion forums, and app analytics.
Remember, it's okay to adjust your results flow based on this evaluation. The goal is to create a roadmap that is both a realistic plan and a valuable tool for accountability.
## In conclusion…
We're so proud of you for taking this step toward understanding and planning the social impact of your indie game studio. By developing a results flow, you're mapping the path from what you do to actually _changing the world_ and creating a vital internal tool that will guide your actions, help you measure your progress, and hold you accountable. Your players, investors, and community will actually love you for it.
You'll revisit, revise, and refine your results flow as your studio grows, as you learn more about your impact, and as the ecosystem changes (because of _you!_). It reflects your studio's values, and you should share it with the world!
We hope we've inspired you to think ever more deeply about the impact of your games and how you make them. Embrace the whole process, refer to your results flow regularly and let it guide your core work.
In the next article in this series, we cover [**creating your impact measurement framework**](/impact-tools/imf).
We can't wait to see the impact you'll make!
#### Additional resources
- [Miro Results Flow template](https://miro.com/app/board/uXjVM4S_rag=/?share_link_id=763577396820)
- Want a quick evaluation of your results flow and ultimate outcome statement? We'd be happy to take a look and provide actionable feedback. [Drop us a line.](mailto:hello@weirdghosts.ca)
- Looking for funding for your impactful game studio? Even if you're just starting your impact journey, [we'd love to hear from you](https://weirdghosts.ca/apply).
#### Acknowledgments
Warm thanks to:
- datejie cheko green of Gamma Space for coining the term "results _flow_" to replace the term" results _chain_." We adopted this term to avoid imagery associated with white supremacy and underscore the fluid rather than rigid nature of the links between outcomes.
- And the support of [Lift Philanthropic Partners](https://www.liftpartners.ca/) for their impact training

View file

@ -0,0 +1,40 @@
---
title: Schedule
description: ''
category: programs
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.231Z'
---
# Program Schedule
## Stage 1 (Months 1-2)
| Activity | Time | Frequency |
|-----------------------------------|--------------------|---------------|
| Workshops and discussions | 2 hours | Weekly |
| Peer Support meetings | 1 hour | Weekly |
| Asynchronous check-ins via Slack | 30 min - 1 hour | Weekly |
| Networking and social events | 1 hour | Monthly |
| Studio development work (outside meetings) | 2-3 hours | Weekly |
| Financial support | $5,000 | |
## Self-assessment
| Activity | Time | Frequency |
|-----------------------------------|--------------------|---------------|
| Evaluate team alignment and program fit | 1 hour | One time |
| Draft plan for Stage 2 | 2 hours | One time |
| Facilitated collective evaluation | 1 hour | One time |
## Stage 2 (Months 3-6)
| Activity | Time | Frequency |
|-----------------------------------|--------------------|---------------|
| Peer Support meetings | 1 hour | Weekly |
| Asynchronous check-ins via Slack | 30 min | Weekly |
| Peer-led workshops and discussions | 2 hours | Every other week |
| Peer workshop preparation and delivery | 4 hours | One time |
| Studio development work (outside of meetings) | 2-3 hours | Weekly |
| Financial support | $20,000 | |

View file

@ -0,0 +1,179 @@
---
title: Self-Assessment
description: ''
category: programs
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.231Z'
---
[Self-Assessment Document](https://docs.google.com/document/d/15og3YqFdMO3o3zr-fbYgwPHgbQnevbxZ7SVCcbjRhc8/edit?usp=drive_link) - go to the File menu and select _Make a Copy_.
# Preparing for Self-Assessment
In today's session, we will discuss the importance of self-evaluation and why taking time for it is necessary. We will cover two types of self-evaluation- **personal** and **studio** self-evaluation.
## Measuring Progress
The expression "what's not measured can't be managed" is often associated with a profit-centred mentality. But measuring things can also be good for improving communication and alignment, as well as assessing progress in a project. In this program, studios assess their values, goals, structures, resourcing, and operational flows to varying extents based on factors such as when and why they started collaborating and how far along their project is. Assessments should always clarify what is already in place for individuals and the collective.
## Building Capacity with Clarity
It's important to have clarity in order to encourage collaborative and equitable participation.
This may seem basic, but it's not always easy. When you have a clear understanding of your goals, everyone can participate more fully. This increased participation leads to building *capacity.* We often forget that the most important resource we have is people, not money. When we achieve clarity, we can increase our *capacity* for participation and work together towards the development of the co-op. The only requirement is to have enough time and space to do so.
## Making Space and Time
All of this work requires **time and space**, and you have already dedicated a lot of both in this first stage of the program. You've made time for meetings, allowed room for thinking, brainstorming, and dreaming, as well as for getting clearer strategically and practically. Some of you even brought more than one member of your studio into these sessions and workshops. Congratulations to those who were able to create that time and space!
For those who haven't yet had the chance to make that time and space, there's still time to do so. We've talked a lot about reflection, and we'll talk more about that shortly.
But reflection isn't really going to help you move forward until you write the things down.
## Writing Things Down
We have created project and studio Miro boards to help you visualize your ideas and work collaboratively. These boards allow you to see the big picture and prioritize tasks accordingly. You can identify top priority items and their dependencies, ensuring that the necessary steps are taken before moving on to the next tasks. This helps you work together more smoothly and achieve your goals faster.
When you write down your thoughts and ideas, assess and evaluate them, and continue to refine them, you are creating pathways to transparency. This is because when you work with a team, or even on your own, you may have certain thoughts and ideas that you may not even be aware of until you put them down in writing.
If one person on the team is only working on what they already know or are comfortable with, without writing it down and sharing it with the rest of the team, they may be working in a way that is not transparent to the others in the team. So, this process not only helps you refine your own ideas but also makes you more transparent and helps you collaborate better with your team.
## An Intentional Practice
This process is also vital to preventing yourselves collectively and individually from making decisions in haste or making decisions out of fear. As we discussed in the decision-making session, making decisions out of fear is never really helpful.
It often leads to having to redirect, correct, troubleshoot, or put out fires or even conflicts that have to be resolved. The time and space put aside for this is really, really key to preventing fear-based or rushed decisions that you will likely regret.
Last but not least, putting together this time and the space to do this work is about building **intentional practice** as opposed to a reactive or uninformed practice, which end up being way more work and way more costly in the long run.
## Personal Assessment
We would like you to begin with a personal assessment, which is a combination of a personal and professional assessment that requires self-reflection. We have developed this assessment over time and tested it on the proto-members of the Gamma Space co-op over a year ago.
**This is only for your personal use and no one else will see it.** The purpose of this assessment is to help you reflect and gain clarity on your personal and professional status, and to establish a baseline for yourself. It will enable you to understand where you stand in your *life*, where you are with respect to your professional work, and what you're being called to do in the role that you're playing in your studio.
All of the studio members come in with a personal baseline, and these provide a basis on which you can begin to align with each other. This helps you all get on the same page because you've all filled out the same questions and have the same understanding.
It's important to do personal self-reflection before joining Stage 2. This will help you assess whether the program is right for you, and if it's helpful at this time. You don't have to talk about your self-reflection with others, but it's essential to go through it yourself.
By doing this self-assessment, you can answer some essential questions, like whether the program is working for you or not. If you find that it's not helpful for you, you can make an informed decision about what to do next.
Asking these questions and being self-reflexive will help you feel clearer about your decisions and identify any cognitive dissonances that you may have with the program, your studio, or even with yourself. It's essential to get with the program and ask these hard questions to make the most out of the peer accelerator program.
### Personal Assessment Overview
The personal assessment has four major sections.
The first part is focused on your project.
The second section is focused on your life.
This is not something most people are asked in job interview in a collaboration project setting.
There's always a default set of assumptions that people make: That you're ready, you have all the supports you need, here we go!
But what we have found (each of us in Gamma Space and Weird Ghosts, and many of the people that we've collaborated with over the last few years), is that if you don't have the supports or stability you need in your life, you either cannot fully participate in the project, or you put a disproportionate amount of pressure on the studio to fill all those roles for you in your life. And so this is just a bit of a reality check and a balance check.
There's also a brief section about co-op integration, which asks you some questions about your own defaults, programming, nature and your choices, priorities, and social behaviour.
Finally, there are a couple of questions about why you want to become a cooperative game studio. This is from your personal-professional perspective once you've had a chance to reflect on those privately by yourself, you can be more clear as you enter into the next stage.
> [Self-Assessment Document](https://docs.google.com/document/d/15og3YqFdMO3o3zr-fbYgwPHgbQnevbxZ7SVCcbjRhc8/edit?usp=drive_link) - go to the File menu and select _Make a Copy_. Remember, no one else will see this  not Gamma Space, not Weird Ghosts, not other members of your team.
## Studio Assessment
After each member finishes their individual self-assessment, it's time to look at your studio assessment. **A template has been added to your studio development Miro board.** This should be completed as a collective and synchronously if possible, since discussion is a big part of the process.
If you just do it sort of by adding points individually, you're probably going to miss out on some of the nuances that people have pulled out in their personal assessment.
It's important that you do this together, and that you make some space and time for it.
We're going to step through the questions so everyone understands what these questions are.
### Step 1: Values
As you probably guessed, Step 1 is about values. We've asked you to list 3-5 value statements that your studio may employ to help further its development.
Review what you already have and see if it's still relevant, or if you need to make some tweaks based on the last few weeks' presentations.
This doesn't have to be super deep and complicated, but it should be something that the whole team agrees with.
### Step 2: Studio Structure
Take a moment to describe your current ideas around your studio structure. Just provide us with some idea of where you might be heading, what responsibilities look like, how investment might come in, how shares might impact value, and if you want to use a value accounting system.
This doesn't have to be a giant list of things it could be a series of sticky notes, or it could be a paragraph.
### Step 3: Decision-Making
In this section, describe your current ideas around decision-making. We would like to see your thoughts at three different levels: At the co-op level, the management level, and at the production level. You might have other levels and other ways to break this down further. We just want your thoughts  there is no "right" answer.
### Step 4: Tools and Process
Describe your evaluation of how your tools satisfy and support your studio's workflows and values. Anything that you collectively have recognized, even thinking about this at a high level, would be really helpful.
How are you deploying new tools and workflows to more effectively and meaningfully achieve the work of your studio? Again, this doesn't have to be something you've really committed to yet, since you're in the early stages.
Some studios have already started implementing what they learned into their work. However, not everyone is at that stage yet. So, if you have something that you have been working on or even just an idea on how to approach this in the future, that would be great.
### Step 5: Storytelling.
How do you see storytelling as valuable to the development of your studio? And how might you deploy storytelling techniques within your studio?
During a recent session, we explored storytelling and how it can be used to make our studio more visible, knowable, and understandable. We discussed techniques like micro-journaling and how they can help document our history and decision-making processes. If you have any thoughts about this topic, please share them. Have you experimented with using your own Discord or Slack channels for this purpose? If so, please describe your experience so that we can learn from each other and improve the process if necessary.
### Step 6: Reflection
Here, reflect on any collective growth or changes in thinking that have occurred as a result of your participation in the Baby Ghosts program. It doesn't have to be a grand epiphany that has completely transformed your life. It's perfectly fine if nothing has changed significantly.
If some aspects of your thought process have been altered or have become topics of regular discussion, it would be great to hear about those changes. There may be a few different ideas based on the experiences of everyone involved, but whatever is shared will be an idea that is embraced by the entire group.
### Step 7: Stage 2 Focus
What specific areas do you want to focus on in Stage 2? This step brings everything together for the next stage of the program. *Even if you feel that there are challenges, it doesn't mean that you can't participate in Stage 2.* It may just require us to work together to find solutions. That's why it's important to be honest about your individual assessment, as some people may have specific needs and challenges that require collective solutions or rethinking.
We have discussed how this work is both iterative and recursive, which means that we'll use what we have learned so far to focus on specific areas in the next few months. These areas can be related to things we have discussed before, or they can be deep dives into decision-making processes, documentation, or specific aspects of your game, such as pitch decks or pipelines. Please take some time to think about what you want to focus on in Stage 2, as it will be customized to your specific needs.
#### Examples
- How to turn our various ideas on processes into a workflow that can help us create a prototype for a game or project we are working on
- How to create a community-based resource
- Reevaluating how we present our services online and how they impact business development.
In the new year, we will customize cohort meetings based on people's needs and interests, and studios can work with Gamma Space and Weird Ghosts folks to set individual goals and plans to achieve them.
## Ranking
At the bottom of each of these on your studio boards, you will find a rating system that allows you to rate the level of depth of the exploration on each of the subjects. This rating system will help us in improving the content. Please rate the exploration from one to five, keeping in mind that there is no wrong answer.
- The first is "Considering/Reflecting," which means you are thinking about the issue in question.
- "Discussing Collectively" means you have discussed the topic with others and made some space for it.
- "Brainstorming" means you have actively planned and worked on the issue.
- "Sifting and sorting" involves prioritizing and making decisions based on the brainstorming information.
- Finally, the fifth is creating the first draft of the documentation around the issue.
It's important to note that we don't expect everyone to have gone through all five steps. So, if you haven't reached step five, don't worry about it. This categorization is just a way to help us understand where you are in the decision-making process.
## Assessing Your Priorities
If you're feeling like you had certain priorities when you applied, such as decision-making or studio structure, and you later found out that you only had time for other things, don't worry. It's important to be honest with yourself about where you are in the process. For example, if you're still brainstorming and at stage three with your studio structure, but you've made progress with your values, acknowledge that. It's important to assess where you are in a non-judgmental way.
It's not supposed to make you feel bad or ashamed or anything like that.
It's just a reality check.
Even if we don't complete a specific task or project, we can still acknowledge the effort put into it. We can also ask ourselves how we feel about the progress we've made. Has it been helpful? Has it brought clarity to the situation? Has it helped to resolve any differences between us? Even if we haven't produced any documentation yet, this exercise can help to create alignment among the group.
So please know that if you're going through this evaluation and you find that you're trying to measure time spent, space made, and these five indicators, none of this is meant to feel bad. If it starts to feel bad or if you start to hear a fellow studio member say things that are kind of dismissive or minimizing, try and help each other to not feel that way.
Remind each other: No value judgments here. This is just an assessment.
This is something that many of us are not very good at, and some of us have never even tried before. These assessments can be unfamiliar and may trigger negative emotions, negative self-talk, or even memories of past negative experiences in school or a workplace. However, this is an opportunity to assess how these things are affecting your current project and goals. Take a moment to reflect and evaluate these factors. Let it breathe.
## Conclusion
If you feel like this is too much work, don't try to force it into a short amount of time. It's better to take the time you need, even if that means breaking the task into two sessions. If you need to talk about this with us, our studio meeting this week is a good opportunity to do so.
When discussing diagnostic vs. high-stakes assessment, it's helpful to think of it as explorative versus terminal. This is similar to what we practiced last week with low-stakes storytelling and communications. This task is also meant to be relatively low-stakes, meaning that disagreements or misalignments shouldn't result in a complete breakdown of working together.
As you discuss with each other, take the opportunity to use the Layers of Effect tool that we introduced, which involves examining the impact of dissonance or issues in the task. Give yourself the time you need to digest and understand any implications that arise from these discussions.

View file

@ -0,0 +1,112 @@
---
title: Stages of Coop Development
description: ''
category: programs
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.232Z'
---
# Stages of Cooperative Development
Some teams have wondered how to tell where they are in the process of building their cooperative. This framework helps you understand the landscape of cooperative development and where Baby Ghosts' support fits.
There is no single "right" path through these stages! Studios are made of humans, and humans move at different paces and have different needs and capacities. Some studios revisit earlier work, and some jump in to multiple stages simultaneously. This framework provides orientation, not prescription.
## Stage 1: Pre-formation
### Relational and governance foundations
This stage is for building the relational infrastructure and governance clarity that will inform all future decisions about your studio.
This means:
- Values alignment - What do we stand for? How do we want to work together?
- Power and identity - Who are we as individuals? How do power dynamics show up in our team?
- Decision-making structures - How will we make decisions together? What needs consensus vs. consent vs. delegation?
- Governance principles - What kind of cooperative culture are we creating?
- Conflict navigation - How will we handle disagreements and tensions?
- Financial transparency - What are our shared expectations about money, compensation, and sustainability?
- Storytelling - How do we collectively share our values, journey, and goals with an audience?
**Most cooperatives fail due to interpersonal and values conflicts, not from lack of funding or technical skills**. This foundational work *prevents those failures, or encourages those failures to happen early* by highlighting misalignments and building collective decision-making skills from the get-go.
This is the Baby Ghosts' Peer Accelerator. The program is designed specifically for this pre-formation work. We provide:
- Structured curriculum on cooperative values and governance
- Peer support from experienced cooperative practitioners
- A community of other studios navigating similar questions
- Tools, frameworks, and reflection processes
**This work typically takes 6-12 months**, though teams may revisit these foundations throughout their studio's life.
## Stage 2: Formation
### Legal structure & incorporation
This stage translates your relational and governance work into legal structures and formal incorporation.
The work you'll do during this stage includes:
- Choosing a specific legal structure (worker cooperative, non-profit cooperative, share corporation, hybrid, etc.)
- Understanding jurisdiction-specific requirements
- Creating bylaws that reflect your governance principles AND meet legal requirements
- Filing articles of incorporation
- Setting up banking, accounting systems, and tax structures
- Understanding compliance requirements
*This comes after pre-formation* because your bylaws and legal structure should reflect the values and governance principles you've already clarified. Trying to do this work without pre-formation often leads to generic bylaws that don't match how you actually want to operate.
This is NOT Baby Ghosts' expertise. We are not lawyers or accountants and cannot provide legal or financial advice about incorporation.
What we CAN do is help you understand how your pre-formation work should inform your formation decisions. We can sometimes connect you with legal and accounting professionals who specialize in cooperatives, share resources about different cooperative structures, and share what other studios in our alumni community have done.
Once you're ready, the legal formation process typically takes 2-6 months, depending on jurisdiction and complexity.
## Stage 3: Early operations
### Implementing your cooperative
This stage is all about actually living and working according to the cooperative values and structures you've created. This is where all the theory you've considered and worked on becomes practice.
During this stage, you'll run meetings using your decision-making structures, explore financial transparency practices, and navigate your first major conflicts with your processes. It also involves building sustainable routines for your team, managing your first major revenue/projects, and adjusting your governance. Having bylaws on paper is very different from living them in practice. Most cooperatives discover they need to refine their structures once they're actually using them.
At this stage, Baby Ghosts can provide informal alumni support. After completing our program, you remain in our Slack community where you can ask questions in your cohort or any community channel, check in on other studios' channels to learn from their experiences, attend ongoing workshops and social events, and access our growing resource library.
*This is NOT formal structured support, but peer-to-peer learning and community care!*
Expect this stage to last 1-2 years of learning and adjustment as you find your footing.
## Stage 4: Mature operations
### Established cooperative
Your cooperative has established rhythms, processes that work, and the ability to navigate challenges. You're focused on sustainability and impact and way past figuring out the basics.
This is the time you might be:
- Onboarding new members
- Doing *long-term* financial planning
- Further refining your governance (yes, this is a neverending process!)
- Contributing to the broader cooperative movement
- Maintaining alignment as team/projects change
Mature studios sometimes:
- Serve as Peer Supports for new cohorts
- Share case studies and learnings
## Understanding where you are
**If you're currently in the Baby Ghosts Peer Accelerator:**
- ***You are in Stage 1: Pre-Formation***
- This is the right time to be figuring out values, decision-making, and governance
- It's **NORMAL** to not have clarity yet on legal structures or bylaws
- The work you're doing now will make formation and operations much smoother
**If you're wondering, "When do we incorporate?"**
- There's no fixed timeline
- Some studios incorporate during or right after the program
- Some studios take 1-2 years of pre-formation work before incorporating
- Some studios decide a cooperative structure isn't right for them (and that's okay!)
**If you're feeling lost about "the steps":**
- This is less like following a recipe and more like learning a language
- Each studio's path looks different based on your context, capacity, and goals
- The "roadmap" is clarifying your values and building governance skills, not checking boxes
**If you're still unclear about where you are in your journey or what work you should be focusing on**, bring these questions to:
- Your Peer Support in your 1:1 meetings
- Program coordinators (Jennie & eileen)
- Your cohort peers who may be navigating similar questions

View file

@ -0,0 +1,280 @@
---
title: Structures for Impact
description: ''
category: strategy
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.223Z'
---
# Choosing an impactful business structure
_Please note: The information in this article is specific to Canadian companies!_
When setting up a studio, one of the first and maybe scariest decisions you'll make is choosing the right business structure. This structure will affect your studio's **governance**, **funding options**, and **growth potential**. Remember that project-based funders rarely care about your studio's structure or sustainability. We've seen them push for hurried incorporation to facilitate their funding. Before you jump to incorporate, consider your studio's long-term goals, where you might seek funding, and the impact you want to make in the world.
If you've already incorporated or worry about needing to before you've had the time to think through all of the possibilities and implications, approach this as if you have lots of time and have not made any irreversible decisions yet.
Of course, the requirements of the big government funders in Canada may influence your decision, but it should not be the only input, and we want you to have a complete picture of your options.
Weird Ghosts believes indie studios should **establish their companies in alignment with their social purpose** instead of being driven by project funding, aka the "old normal" that leaves no room for new founders to create a solid foundation.
## Results flow
A [results flow](/impact-tools/results-flow) is a roadmap describing the impact you want to make and the activities youll need to carry out to achieve it. If you have the chance, draft your results flow before deciding on the form of your studio. It may make your choice a lot easier.
In addition to helping you identify the most appropriate business structure, your results flow also:
- Helps you create your impact measurement framework (IMF), allowing you to monitor progress toward your key outcomes
- Forms the foundation of your business plan and helps you develop and evaluate your business model
So, super handy if you're preparing to pitch investors or publishers!
## Blended returns
Blended returns combine financial and social returns and are at the heart of Canada's $755 million [Social Finance Fund](https://socialfinance.fund). You have a few options when selecting a business structure that will provide blended returns and set you up to access social financing:
::list
- **For-profit** structures like socially responsible corporations
- **Co-operative** social ventures
- **Non-profit** organizations and co-ops
- **Charities**, and social purpose businesses
::
Whichever path you choose, remember that incorporation will affect your governance structure and your ability to secure investment and other types of funding. It also may preclude you from accessing certain kinds of investment. For example, non-profits cannot offer share capital and will typically need to look to debt financing. And a for-profit that values social return over financial may be a hard sell to traditional investors.
Whether you decide to incorporate as a for-profit company, a non-profit, or a co-op, demonstrating both financial and social returns will be a requirement if you intend to seek social finance investment.
![Blended returns diagram](/content/structure/blended-returns.png)
The purpose of a corporation is to generate financial returns. Looking at different types of corporations on a spectrum, you'll find "pure" commercial operations on one end. The only thing those shareholders and investors care about is making money. They will not care about a social impact report.
Next, we have the socially responsible corporation. It's hard to find a company in 2023 that doesn't at least pretend to have a corporate social responsibility policy… because branding and reputation. Lockheed Martin? Even they "give back" to the community by [training underprivileged youth](https://www.lockheedmartin.com/en-ca/features/social-impact-stem.html) so that they may someday, uh, work on hypersonic missiles and fighter jets.
If we keep moving to the right of the diagram, at the end we find that even charities can start a social venture, as long as it aligns with its mandate and strict government regulations.
While demonstrating financial _and_ social returns sounds like a lot and it is a bigger job than non-social-purpose companies have the benefit of social finance is that it is structured to be easier for mission-driven organizations to access and manage. So, for example, you will get lower interest rates, more flexible repayment schedules, and possibly zero-interest recoverable grants. Work with investors or funders who fundamentally understand this.
If you can demonstrate solid financial returns, equity investment from a social investor may be possible. But you will have a hard time capturing the interest of a venture capitalist (VC) without the potential for a very high return on investment.
> You may be thinking, "We probably won't be able to generate a financial rate of return at or above market."
> Hey, that's okay! You can focus on investors and partners who will structure a deal with you that isn't equity-based, like low-interest loans or royalties — or Weird Ghosts' [SEAL agreement](https://weirdghosts.ca/blog/how-we-make-investments)
## Understanding SPOs
You may be a social purpose organization (SPO) if you are working on advancing **social, cultural, or environmental objectives**  such as transforming an industry or making an economic impact within a specific community. To access funding from social finance investors, such as Weird Ghosts, you must put impact at the **core** of your mission and operations.
You're here because you're interested in changing what a "normal" video game studio or startup looks like. There's no set template!
So before getting into the different form options for your SPO, take a minute to think about the following:
#### Intention and motivations
**Which takes precedence profit-making activities or furthering a social purpose?**
While the goals of making money and furthering a social purpose are not mutually exclusive, their relative importance will influence the optimal structure as they will often conflict during your studio's life.
::alert{type="info"}
**Hint:** look at outcomes on your **results flow.** Which is emphasized?
::
Knowing what's most important is critical to choosing a structure that either gives you the flexibility to respond to financial opportunities or ensures your social purpose remains central in decision-making.
Not-for-profit and unincorporated social ventures **cannot seek equity financing** and may experience other barriers once the venture grows.
#### Control
**Are you open to sharing control? Can you operate and fund the studio independently?**
Members in a co-op and investors split control and priorities may conflict.
For-profit companies are responsible to shareholders, which can cause pressure to favour financial returns. Because there is no legal way to enforce a social purpose within a for-profit corporation, maintaining a focus on social benefit depends on successive leadership sharing the goals of the original founders.
In a co-op, founding member(s) do not maintain control. Co-ops are legally required to operate on a co-operative basis so they can talk about their community-benefit purpose, but maintaining member participation over time can make management more challenging.
Non-profits won't have investors with conflicting priorities because they do not issue share capital. Social finance investors offer affordable repayable capital and expect social return on investment (ROI) -- and to be repaid.
#### Market
**What is the profit potential based on the services and products you intend to provide? Who will be your primary customers funders or end-users?**
If you focus on providing services such as design and development, your profit potential is different from a product-focused studio.
If you expect it to be relatively easy to be profitable, incorporating as a for-profit makes more sense regardless of how your money is spent. If, by contrast, you expect the venture to be challenging to sustain without donations and grants, then a non-profit structure may be more appropriate.
Non-profits are subject to restrictions on the types of business activities they may carry out. The CRA does not want a non-profit to compete with products and services provided by for-profit organizations.
#### Capital
**Will you seek investors expecting a financial return? Can you rely on debt financing? Do you plan to reinvest profits or donate them?**
The funds needed at start-up may influence the structure of the venture.
Greater needs for capital and financing flexibility — and in particular, the need to be able to issue share capital — will suggest a for-profit structure.
Non-profit organizations and charities cannot generally access share capital and must rely on debt financing. If you do not hold assets you can borrow against, it may be hard to obtain commercial loans. (Upside is tax exemptions, but this is not super useful if you do not hold assets or wish to present your studio as non-profit.)
Co-ops must operate as close to a cost-recovery basis as possible. Co-ops are generally designed on the assumption that the majority of the organization's capital will come from the members. However, co-ops are permitted to issue shares and loans to non-members, with the promise of at least a limited financial return on investment. This aids in attracting capital from outside the membership structure if necessary.
## Hybrid
Weirdly enough, "social ventures" and "social enterprises" are not real things! Sort of…
Despite the [Social Finance Fund](https://www.canada.ca/en/employment-social-development/news/2023/05/government-of-canada-officially-launches-the-755m-social-finance-fund-to-advance-the-growth-of-the-social-finance-market-in-canada.html) launching in May 2023, plus a couple decades of social enterprise scholarship and practices, "social enterprise" is not a legal structure in Canada. In fact, current federal and provincial legislation doesn't offer _any_ legal structure combining the perks of both the for-profit and non-profit corporations.
But we have lots of options and flexibility when it comes to defining how our companies operate, get financing, and grow sustainably, ethically, and in line with our communities' needs.
And hybrid entities do exist:
- In B.C., you have the [Community Contribution Company](https://news.gov.bc.ca/releases/2013FIN0067-001172) (CCC or C3) and [Benefit Company](https://www2.gov.bc.ca/assets/gov/employment-business-and-economic-development/business-management/permits-licences-and-registration/registries-packages/information_package_for_benefit_company.pdf) (PDF).
- In N.S., you have the [Community Interest Company](https://novascotia.ca/just/regulations/regs/ciccomminterest.htm).
- And across the country, [B Corporation](https://www.bcorporation.net/en-us/) certification is also an option.
These hybrid structures come with additional reporting obligations and may require amendments to your articles of incorporation. Restrictions on the use of capital can also hamper your funding and financing options.
## Co-op
Co-operatives, or co-ops, are a unique business model distinct from business corporations. They were originally intended as a way for people to share resources and are designed to promote equity, create a healthy work environment, and support collaboration.
> "A co-operative is a legally incorporated corporation that is owned by an association of persons seeking to satisfy common needs such as access to products or services, sale of their products or services, or employment."
> [Innovation, Science and Economic Development Canada](https://ised-isde.canada.ca/site/cooperatives-canada/en/information-guide-co-operatives##what)
**They can be for-profit or non-profit**, and their goal is to minimize business costs to allow more people to participate. You can incorporate your co-operative either federally or provincially/territorially  but there are some geographical differences in regulations (especially in Quebec).
Even if a co-op is non-profit, it can still charge for its products and services. However, any profits made must be reinvested into the business.
Four broad categories differentiate co-ops from share (business) corporations: ownership, directors, voting, and profit.
#### Ownership
- **In a co-op, shares cannot change in value.** When members join, they buy shares at par value, which doesn't change even if the business is wildly successful (or fails).
- **Membership shares can't be transferred as freely as in a business corporation.** A co-op share cannot be sold to anyone else and can only be bought back by the co-op at the same value the member originally bought the share at.
- **Ownership is independent of value.** The amount of ownership is determined by the number of membership shares held.
- **Members sell their shares back when exiting.** If a member wants to exit a co-op, their share must be repurchased at the same value the member initially bought it at. If the co-op doesn't have enough money, they can enter into an agreement where the co-op pays you out over time.
(In contrast, a business corporation is owned by shareholders who invest money and receive shares in return. These shares can increase or decrease in value depending on the business's financial health. Shareholders have voting power proportional to the number of shares they hold.)
#### Directors
The number of directors required varies across Canada, typically three. Directors are responsible for the day-to-day governance of the co-op and must always act in its best interests.
#### Voting
In a co-op, the core value is "one member, one vote," no matter how many shares are held. This contrasts with a business corporation, where the number of votes can increase with the number of shares held.
In a federal worker co-op, each member has to be an employee. There's also a rule that 75% of the membership must be employees, but the other 25% can be investment-type shares issued by the co-op.
#### Profit
When a co-op makes a profit and distributes it to its members, it's called a "patronage return" — similar to a dividend. Someone who has five membership shares will be entitled to more surplus than someone with one membership share. But again, holding more membership shares does not increase your number of votes.
A surplus remains after all costs, including operating and general reserve (and bonuses or patronage returns if you choose), have been covered.
While co-ops can accept investments, they're traditionally not profit-oriented entities. This lack of a profit-driven structure and limited shares can restrict growth and deter some investors. Be sure you're okay with that.
> That being said… we believe co-ops are _the_ worker-centric structure of choice, and were proud to have invested in Montreal-based worker co-op [Lucid Tales](https://www.lucid-tales.com). And our first Baby Ghosts grantee was Winnipeg-based co-op [Something We Love](https://somethingwe.love)!
#### Questions to ponder
When thinking about forming a co-op, consider the following:
- How will you handle surpluses at the end of the year?
- How will you manage the governance of your co-op?
- What happens when someone wants to exit the co-op?
- How will you handle disputes?
A [thorough guide to federally incorporating a co-op](https://ised-isde.canada.ca/site/cooperatives-canada/en/information-guide-co-operatives##how), and contact information for provincial associations can be found on the ISED site. If youre in Quebec, you can find more information at [Ministère de l'Économie, de l'Innovation et de l'Énergie](https://www.economie.gouv.qc.ca/objectifs/informer/cooperatives/) or get help from le [Réseau Co-op](https://reseau.coop/).
## Non-profit
Non-profits and charities can be structured in a few different ways. The most common is to be a _corporation without share capital_. They have no shares or shareholders but members who vote for directors. Members don't get dividends and (usually) don't get any of the corporation's assets if it dissolves.
These types of corporations _must have a social purpose_. **All** of their activities must support this purpose.
There are laws about how charities and non-profit organizations can earn money:
- Canada's Income Tax Act says these organizations can only do certain activities to make money if they want to stay tax-exempt.
- If a charity carries on a business that doesn't relate to its purpose (unless run mainly by volunteers), it can face penalties, including losing charity status.
- If a charity or non-profit wants to make money to support its mission, it _may_ have to use a separate business corporation to do the activities. [Learn more.](https://www.canada.ca/en/revenue-agency/services/charities-giving/charities/policies-guidance/policy-statement-019-what-a-related-business.html)
## Sole proprietorships & partnerships
A sole proprietorship is an unincorporated business owned by a single individual. The business and the operator are the same.
It's the simplest (and therefore most popular) structure, with minimal or no setup requirements. Your business losses can be deducted from your other sources of personal income. However, this structure only works for a solo dev. You'll face **unlimited personal liability** and challenges raising money. Bootstrapping (using your own money) or loans are possible sources of startup funding.
A partnership is the same as a sole proprietorship, except it's between two or more people. General partners also risk **unlimited personal liability**, and you'll have difficulty finding appropriate financing.
## Business corporation
A business corporation is a standalone legal entity with rights and responsibilities (just like individuals). They can own property and enter into contracts. They are owned by shareholders and operated by directors and officers.
Shareholders are not responsible for a corporation's debts. They benefit from lower corporate tax rates and can raise capital more easily than partnerships or sole proprietorships. Unfortunately, business corporations are more expensive to form and operate because of stringent regulatory requirements.
A business corporation's structure includes the following:
- **Shareholders**: Own at least one share of a corporation's stock. Collectively, they own the corporation and get to vote on key business decisions. There can be different classes of shares and shareholders.
- **Directors**: Elected by shareholders and are responsible for operating and managing the business.
- **Officers**: Act on behalf of the directors to operate and manage the business. They must be registered and are almost always employees of the corporation.
A major limitation of a business corporation is that there is **no real way to build social purpose** into the governing documents. Successive directors may change or eliminate the social purpose your founders established.
## None of these is quite right…
If none of the existing legal structures perfectly fits your needs, you could use ancillary agreements, policies, and covenants. Your values, ethics, and core principles are also a governance layer on top of your business structure. You can combine different structures and governance models to create a business that aligns with your ultimate outcome.
Some questions to ask yourself if you go this route:
- Is your governance model easy to understand and accessible for diverse stakeholders?
- How do you make decisions?
- Who has a right to participate or vote?
- Who represents whom?
- How can you solve conflicts?
- How do you communicate your governance? Who needs to know?
#### Some inspirational alternatives
- [Distributed co-operative (DisCo)](https://disco.coop)
- [Platform co-operative](https://platform.coop/)
- Community-centered business, where stakeholders who don't own shares directly can participate in governance, such as through a stockholding trust designed to represent their interests. [More info](https://georgetownlawtechreview.org/wp-content/uploads/2021/05/Mannan-Schneider-Exit-to-Community-5-GEO.-L.-TECH.-REV.-1-2021.pdf) (PDF).
- For-profit corporation with co-operative decision-making policies… wait, what?!
#### A co-operative corporation?
Suppose you decide to form a business corporation but wish you had the benefits of collective decision-making. In that case, you can structure it so that everyone is an equal owner with an equal say in the company nothing prevents a corporation from having employee shares. This flexibility allows a corporation to operate similarly to a co-op without being legally bound to a co-op's structure. Some examples of corporate-co-op studios include Future Club[^2] and KO-OP[^3] (in the process, as of 2023, of converting to a Quebec co-op).
In your shareholders' agreement, you can include language that prioritizes collectivity, outlines dispute resolution procedures, and details processes for managing a voting deadlock.
You could also consider encouraging your employees to form a union! 👀
**Healthy studio culture can be promoted in any organization.**
> Tip: Establish a founders' agreement before your company is officially formed. That way, you have processes in place for dispute resolution at every stage of your studio's development.
[^2]: [A Worker-Owned Game Studio Rises from the Wreckage of Skullgirls Developer](https://www.vice.com/en/article/7kpymg/a-worker-owned-game-studio-rises-from-the-wreckage-of-skullgirls-developer)
[^3]: [Ko-Op by Name, Co-Op by Nature](https://www.gamesindustry.biz/ko-op-by-name-co-op-by-nature)
## Exit strategies
For traditional startups, the exit is _everything!_ It's the key outcome founders seek. But that's not you. 😉
It might seem weird and pessimistic to plan for the end of your studio. But it is part of how you can take responsibility for the lifecycle of your studio. Who benefits when your studio is bought by Streamberry? Who ends up with your IP and community infrastructure?
Here are some situations where you might face an exit:
- Someone might want to take over the enterprise (maybe even a co-founder).
- You might be so successful you want to sell off the business and start something new.
- You might want to retire! haha
- If the app you make or service you provide becomes something your community depends on, you might want to transfer ownership to your community. One option is an "[exit to community](https://www.colorado.edu/lab/medlab/exit-to-community)," an intentional plan where ownership is transferred to a community that manages and benefits from it. This means the studio stays in the hands of those who built it.
Investors will want to know how you think about your exit strategy. Especially if your financial returns are not high, they will work with you to structure a deal that considers this. Please put it in your business plan.
## A final note
Our best advice? **Go get legal advice!** We love and recommend Alex Chun at [Dickinson Wright](https://www.dickinson-wright.com/our-people/alexandria-chun?tab=0) in Ontario. If you need a referral for another province/territory, [please get in touch](mailto:hello@weirdghosts.ca), and we'll do our best to source one through our networks!

View file

@ -0,0 +1,162 @@
---
title: Telling Your Story
description: ''
category: studio-development
tags: []
accessLevel: member
author: Weird Ghosts
publishedAt: '2025-11-10T10:52:42.625Z'
---
# Telling Your Story
_developed by datejie cheko green_
We invite you to consider the question, "As a creative person, why do you do what you do?"
As you answer this, you'll find yourself *storytelling*.
Let's talk about telling the story of your studio.
## Overview
A studio is a group of people who collaborate with each other and have a relationship with one another. Sometimes, people in a studio want to express themselves, tell stories, or create images that represent their identities. Some people want to create change for others who may not resemble them. This is called "solidarity consciousness."[^1]
The notion of solidarity consciousness is framed in terms of relationships  but the first relationship we have to take care of is with ourselves, and we can expand from there.
Through your storytelling about why you do what you do as a creative, you likely expressed some kind of value that you truly believe in that's core to your sense of purpose and creativity. Our studio relationships are based on values, and we need to put our values into practice and then practice that over and over again.
## Storytelling as a Practice
We can approach telling our studio story as a practice of micro-storytelling. This is not something that most of us think about or deconstruct even people who are used to telling stories all the time.
Journaling is a daily practice that allows for an iterative and daily approach to self-exploration, allowing us to explore ourselves in small doses.
By using our values as our touchstone, we can consistently prioritize building relationships with others. We interact with people on a daily basis, and even small interactions can contribute to the larger goal of creating a community. By engaging in iterative storytelling and practicing this skill, we accumulate experiences and ideas as we make our games. This development process can be enjoyable and rewarding!
We have become documentation-ready by practicing journaling. And by journaling, we don't just mean personal journaling but also **collaborative journaling** for our studio. By keeping our journal entries in a digital space where they won't be deleted or lost, like disappearing messages on our phones, we are documenting our progress as we go. This makes us prepared and ready for any future documentation needs.
Journaling allows us to:
There are two parts to each aspect of storytelling: naming and engaging.
## Who
### Naming
Naming *who* involves identifying the storytellers. In our studio, all members are storytellers, not just the marketing person. The goal is to share the stories of each person's labour, engagement, interpretation of values, expression of values, and practice of values. The audience starts with us, the studio members and collaborators, and then ripples out to the community and players.
### Engaging
Engaging with the audience is about building relationships. Communication is key to building relationships. We've all experienced relationships that fell apart due to poor communication, miscommunication, or a lack of communication. On the flip side, we've also experienced beautiful relationships where communication was valued, prioritized, and practiced, even during difficult times. Engaging with the audience means practicing communication to build relationships.
This process obliges us to attribute the story to the teller. Collaborative journaling requires finding the source of the information and giving proper credit.
## What
### Naming
When it comes to communication, especially on social media, we need to be honest with ourselves that a lot of what we engage in today is not true two-way communication. Some of it is asynchronous, but a lot of it is just sending out messages without any real interaction.
Authentic communication and storytelling require a call and response. It's not just about one person talking and others listening, but rather a back-and-forth exchange of ideas and thoughts.
### Engaging
We initiated this article with a question, and you responded. In a group setting, you can engage others about your thoughts and motivations. That's the beauty of communication and storytelling lots of listeners and lots of reflection back. By offering your thoughts and being present, you can show that you care and are engaged in the dialogue.
Writing is also an important part of communication. It's not just about putting words on paper but instead writing with the intention of being heard and wanting someone to respond. Rewriting and recreating what we write helps us build the story of our studio. We can reflect on what we wrote on Monday, think about it on Tuesday, and then come back to it on Wednesday with new ideas or changes. This process helps us create a more cohesive and engaging story.
## When
### Naming
*When* can be challenging, as it may be something that few of you have considered before in the context of your studio - daily journaling. The word "journal" comes from "dyeu-," which means "today" or "one day." The important thing is to make it a daily habit.
Doing journaling in daily doses means that you can allow yourself to work in small chunks it doesn't have to become everything, it doesn't have to become overwhelming. But it does have to be a discipline of daily practice.
Some recommendations say to start the day with journaling, which helps you to set the agenda for the day. At the end of the day, it offers you an opportunity to reflect back on the day.
It's truly an amazing practice to be able to distill your thoughts and emotions. When you can do it in a collaborative and shared way, such as typing it out, speaking it into a voice note, or drawing it into a visualization, you not only learn about yourself but also about your fellow studio members.
### Engaging
Engaging daily means that you have time for incremental change. It's just tiny doses, so you can iterate and tweak daily. This also gives you time to ask for help and receive it. If you wait and hold onto something, it can become a bigger issue than it really is. Then, it becomes difficult to ask for help and even more embarrassing to receive it. But if we work on it daily, it becomes a routine, and we have time to become clear about our messaging. As we go through it, we grow, shift and change. We realize that something that was a goal two months from now can be achieved sooner if we work on it daily.
## Where
### Naming
This is very, very important: You want to begin your creative journey in safe, shared studio spaces that are visible only to your team and not accessible to the public. This is not a platform for public journaling but rather a low-stakes, internal space that is secure and private.
Once you have established a safe physical space, you can move on to creating safe online spaces that you own and control, such as a website or a newsletter. This ensures that your work is not misrepresented or taken out of context by others.
After you have refined your work and messaging, you can then take it to a public space, such as a pitch, press release, or social media platform. By following this process, you can ensure that you are fully prepared to share your work with the world in a way that is safe, effective, and true to your vision.
### Engaging
Always ensure that it is dialogical in a conversation, there is a speaker and a listener who respond to each other. Start with low-stakes topics and gradually move towards high-stakes ones. This order is important but often overlooked. We need to rethink the way we use technology in our conversations.
## Why
### Naming
Collaborative journaling is a great practice to improve your writing skills. It's not about achieving perfection but rather striving for clarity. Writing is a process of *rewriting*, and it may seem painful at first, but it's a low-stakes practice that can be improved through open collaboration, such as in Slack or Discord channels. This kind of practice builds mutual understanding and trust, which are essential in preventing conflicts, hurt, fear, and trauma.
To express yourself effectively, **ask for feedback** and **try to understand how others perceive your message**. If you're not being understood, break down your message into simpler terms.
Building trust is everything in creating caring relationships, which make way for healing. This is especially important in the context of game development spaces, which can be toxic and traumatizing. It's important to be kind to ourselves and each other and to practice mutual understanding and trust.
### Engaging
Our purpose in exploring *why* is to regenerate healthy environments and practices. These are the things that create clarity.
We're not doing it as a one-time thing; we're doing it on a daily basis. And that's storytelling. Storytelling creates understandings that create healthy environments. And when we do it regularly, we regenerate that very healthy environment. It's like feeding the soil. And it definitely feeds our spirits.
Documenting the journey to clarity leads to great stories. That means the daily practice gets documented; the journey to the same clarity, care, and understanding gets documented.
## How
The "how" is always tricky because it can feel deeply personal. We all have our quirks. We all have our preferences; we all have ways that things work for us in certain ways. But we're also all very creative people. And in games, most of us are good at troubleshooting.
### Naming
Naming the "how" means trying to create a consensus on how all of the studio members are going to participate in this collaborative journaling practice. What kind of bite-size contribution can each member make? What kind of contribution would make them *happy* to make? What would bring joy? And how can we find a way to be dedicated to this? Once you know, share it with your team  it could be helpful!
These generate daily rituals that are centred around the studio's values. We bring the values back in because they are the absolute touchstone of why you are collectively doing what you're doing.
### Engaging
There are many tools available. If you're a developer, you may have the ability to create your own tools. However, tools are only useful if they support relationships and growth. If tools *replace* relationships, they can stymie growth.
Planning your documentation in advance can help ensure that it serves as a valuable source of information and stories that contribute to a longer, more complete, and concise narrative. Those bits and bytes of information become available to you to analyze. There's always an app for that part, right?
This narrative forms the building blocks for your pitch to funders, audiences, collaborators, and communities. It also informs reporting, such as an annual report, financial report to an investor, or to your future self. Think of it as reporting forward. If you are planning ahead, you are reporting to your successor.
Who do we want to support and promote while we progress? This way, as we build our cooperative environment and share our stories, we also understand that if one person falls ill, someone else knows all about their contributions and can fill in. Similarly, if someone needs a break or decides to pursue a different path, someone else knows what to do, how to do it, and why it is done. This way, if someone needs to be replaced or compensated, it's clear who can take over.
## Outcomes
- The medium is the message, the process is the product
- Creates space and time for alignment of understanding
- Produces micro-documentation as the building blocks for your stories
- Builds consensus, understanding, agreement and investment in studio values
- In-studio confidence is beautiful for your creativity, and it ripples out
The medium itself conveys a message. Journaling emphasizes that the process we engage in ultimately shapes our product. Rather than being driven solely by product outcomes, this approach encourages **relationship-building**, which becomes evident in the final product/game/community you are creating.
Collective journaling creates a space for micro storytelling in low-risk settings, allowing for gradual alignment and understanding. This method yields micro documentation, forming the foundation of our different storytelling directions. It not only creates a shared understanding and consensus but also deepens each member's commitment to the studio, its relationships, and your collective values. The confidence gained within the studio improves creativity and makes a social impact on your community and beyond. This is just one approach to shaping your studio's narrative.
## Conclusion
Storytelling in game development goes far beyond the games we make. It's about the shared experiences and values of our team, woven into our studio's identity through daily practices like journaling and open communication. This approach isn't just about documenting our journey; it's about growing together and connecting with our audience in a meaningful way. By embracing this narrative, we're not only crafting games but also forging genuine connections and making an impact that echoes beyond our studio walls.
## Questions to Consider
- How do we pitch projects that are not made to create revenue?
- How do we ensure decolonial language engagement and relationships?
- How do we be authentic to ourselves, to each other, to our studio values and still communicate professionally to funders?
- How do we communicate our studio structure?
_This content was developed by datejie and [Gamma Space](https://gammaspace.ca) for a 2023 Baby Ghosts cohort presentation. We have summarized and adapted it here._
[^1]: a term coined by datejie cheko green

View file

@ -0,0 +1,72 @@
---
title: TikTok Meeting Notes
description: 'TikTok Marketing Meeting: July 3, 2023'
category: strategy
tags: []
accessLevel: member
author: Baby Ghosts Team
publishedAt: '2025-11-10T10:42:09.230Z'
---
# TikTok Marketing Meeting: July 3, 2023
## Questions and answers:
- **Is it valuable to edit things inside or outside of TikTok?**
- Can edit in InShot or Premiere or CapCut whatever youre most comfy with.
- But use the TikTok tools. Use the captions, the sounds, the effects in TikTok (for the SEO)
- Repost other peoples stuff.
- **Whether gameplay or talking heads works better?**
- Really depends on how it's done
- Usually better to be really short & really contained unless it really has some meat to it (like a personal story that will connect with people)
- **Projections for how viable TikTok is?**
- No idea what will happen, but making stuff that is cross-platform can help
- Focus on making vertical video not just TikToks because vertical video are gonna be here for a while
- **I wanna learn about sounds or use original audio or use trending sounds**
- You do want to jump on the trending sounds if you can but sometimes it's good to use your original audio if it's hitting a niche
## Eileens Presentation
[Check out here](https://docs.google.com/presentation/d/1l03RI4uCwAX7eRv9dwJ36i7RuLpYSMO83vqBhkJXzrQ/edit?usp=sharing)
## Daffodil:
- Views numbers are generally below 1000
- Quick 5 second one was the first to get over 1000 views
- One with trending audio & loop really popped off on Instagram
- One got flagged as dangerous and another got flagged as performed by professionals
- Better to get on a trend earlier in the spike rather than later: [Link](https://ads.tiktok.com/business/creativecenter/inspiration/popular/hashtag/pc/en)
## Dunc:
- Been doing vertical social media for people since 2016
- Recommends using all the social media with the same content. Repurpose!
- He has even re-uploaded directly from TikTok to YouTube with TikTok watermark and its been successful
- Best practice is to upload it clean (without watermarks)
- RNG you're dealing with where you can upload the same video and it will do differently
- You get another shot on net if you post the same thing to a different platform
- Try to fill up the vertical space as much as you can
- All platforms are optimizing to vertical
- There are really good ways with games especially to spread your assets out without superzooming on your trailer.
- Have assets in top and bottom wooshing by while regular trailer played in the middle (to make the horizontal video work in a vertical way)
- Can do a blur on the top and bottom in Premiere
- But be careful that the important parts aren't cut off by the captions at the bottom!
### SEO:
- Venba a good example as well as Sally
- Hidden text:
- Hide the SEO text in the image so no one really sees (!!)
- Great if the captions don't really match the aesthetic
- You can overdo it. Too many hashtags, end up being shadowbanned for spamming.
- Do a series:
- Many posts about characters
- Plan in a series to make it easier to plan what you're doing next
- Could be beneficial to make separate accounts
- Studio account / game account
- So you have more chances
### Funnel of content:
- 10 seconds of story (too many Instagram stories are bad)
- 1 minute reel
- longer YouTube video
- We can boost one another / comment on each others videos and ask questions.

64
docker-compose.yml Normal file
View file

@ -0,0 +1,64 @@
version: '3.8'
services:
# MongoDB Database
mongodb:
image: mongo:7
container_name: wiki-mongodb
restart: unless-stopped
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: changeme
MONGO_INITDB_DATABASE: wiki-ghostguild
volumes:
- mongodb_data:/data/db
- ./docker/init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro
networks:
- wiki-network
# Wiki Application (for local development)
# Uncomment to run the app in Docker
# wiki:
# build: .
# container_name: wiki-app
# restart: unless-stopped
# ports:
# - "3000:3000"
# environment:
# MONGODB_URI: mongodb://admin:changeme@mongodb:27017/wiki-ghostguild?authSource=admin
# NODE_ENV: development
# depends_on:
# - mongodb
# networks:
# - wiki-network
# volumes:
# - ./app:/app/app
# - ./server:/app/server
# - ./content:/app/content
# Optional: Mongo Express for database management
mongo-express:
image: mongo-express:latest
container_name: wiki-mongo-express
restart: unless-stopped
ports:
- "8081:8081"
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: admin
ME_CONFIG_MONGODB_ADMINPASSWORD: changeme
ME_CONFIG_MONGODB_URL: mongodb://admin:changeme@mongodb:27017/
ME_CONFIG_BASICAUTH: false
depends_on:
- mongodb
networks:
- wiki-network
volumes:
mongodb_data:
driver: local
networks:
wiki-network:
driver: bridge

View file

@ -0,0 +1,523 @@
# Obsidian Vault Setup Guide
**For:** Wiki-GhostGuild Content Contributors
This guide helps you set up and work with the wiki-ghostguild content folder as an Obsidian vault.
---
## Quick Start (5 minutes)
### 1. Clone the Repository
```bash
git clone https://git.ghostguild.org/org/wiki-ghostguild.git
cd wiki-ghostguild
npm install
```
### 2. Open Obsidian
- Open Obsidian
- Click "Open folder as vault"
- Navigate to: `/path/to/wiki-ghostguild/content/articles/`
- Click "Open"
### 3. Install Required Plugins
The vault has plugin configurations ready, but you need to **manually install the plugins first**:
**Step 1: Enable Community Plugins**
1. Go to **Settings → Community plugins**
2. Click "Turn off restricted mode" (if you see this)
3. Click "Browse" to open plugin browser
**Step 2: Install Obsidian Git**
1. Search for **"Obsidian Git"** by Vinzent03
2. Click "Install"
3. Click "Enable"
4. ⚠️ Important: Restart Obsidian or reload the vault
**Step 3 (Optional): Install Linter & Templater**
1. Search for **"Linter"** by plexus
2. Install & enable
3. Search for **"Templater"** by SilentVoid
4. Install & enable
### 4. You're Ready!
The vault is now configured and ready to use. Wikilinks, images, and Git integration are all set up.
---
## Understanding the Setup
### What's Configured
| Feature | Setting | Value |
|---------|---------|-------|
| **Attachment Folder** | Saves images to | `/public/img/` |
| **Wikilinks** | Enabled for | `[[Page Title]]` syntax |
| **Auto-linking** | When renaming | Updates links automatically |
| **Git Integration** | Via plugin | Obsidian Git (auto-pull on startup) |
### How It Works
1. **You write** in Obsidian using wikilinks: `[[Page Title]]`
2. **You paste images** which auto-save to `/public/img/`
3. **You commit** via Obsidian Git: `Mod+Shift+G` (or menu)
4. **Build transforms**: Wikilinks → `/articles/page-title`, images → `/img/filename`
5. **Readers see** proper links and images in browser
---
## Creating & Editing Articles
### Creating a New Article
**Option A: In Obsidian**
1. Create new file: `Cmd+N` (Mac) or `Ctrl+N` (Windows)
2. Use Templater plugin if available (shortcut: `Mod+T`)
3. Add frontmatter (see template below)
4. Write content using wikilinks freely
**Option B: Use Template**
Start with this frontmatter:
```yaml
---
title: "Article Title Here"
description: "Brief description for preview/SEO"
category: "strategy" # or: funding, operations, programs, templates, studio-development, accessibility
tags:
- baby-ghosts
- p1 # or p0, p2
accessLevel: "member" # or: public, cohort, admin
author: "Author Name"
publishedAt: '2025-11-10T11:13:26.520Z'
---
# Article Title Here
Write your content below...
```
### Key Frontmatter Fields
| Field | Required | Options | Example |
|-------|----------|---------|---------|
| `title` | ✅ | Any string | `"Accessibility Guide: Disability"` |
| `description` | ⭕ | Any string | `"Guide for studios..."` |
| `category` | ⭕ | See list below | `"accessibility"` |
| `tags` | ⭕ | Array of strings | `["baby-ghosts", "p1"]` |
| `accessLevel` | ⭕ | `public`, `member`, `cohort`, `admin` | `"member"` |
| `author` | ⭕ | Name string | `"Baby Ghosts"` |
| `publishedAt` | ⭕ | ISO date | `'2025-11-10T13:00:00Z'` |
**Categories:**
- `strategy` - Strategic planning
- `funding` - Financing & grants
- `operations` - Day-to-day operations
- `programs` - Program descriptions
- `templates` - Reusable templates
- `studio-development` - Studio building
- `accessibility` - Accessibility guides
---
## Writing Content
### Linking to Other Articles
**Use wikilinks - they're cleaner in Obsidian:**
```markdown
See the [[Communication Norms Document for Game Studios]]
Or [[P1 - Publishing & Marketing Playbook for Game Studios|shortcut text]]
```
Obsidian shows these as links. At build time, they transform to proper `/articles/slug` links.
**Why this works:**
- ✅ Wikilinks work in Obsidian's graph view and backlinks
- ✅ You get autocomplete when typing `[[`
- ✅ Renaming articles updates all links automatically
- ✅ Build transforms them to standard markdown for the web
### Adding Images
**Simply paste into Obsidian:**
1. Copy image (or screenshot)
2. Place cursor in article
3. Paste: `Cmd+V` (Mac) or `Ctrl+V` (Windows)
4. Obsidian prompts for filename
5. Image saves to `/public/img/` automatically
**Use descriptive filenames:**
- ✅ Good: `meeting-workflow-diagram.png`
- ❌ Bad: `image1.png`, `Screen Shot 2025-11-10.png`
**Wikilink syntax:**
```markdown
![[meeting-workflow-diagram.png]]
```
Or with alt text:
```markdown
![[meeting-workflow-diagram.png|Workflow for facilitating meetings]]
```
### Code Blocks
Standard markdown fenced code blocks work great:
````markdown
```python
def hello_world():
print("Hello, GhostGuild!")
```
````
### Tables
```markdown
| Feature | Benefit |
|---------|---------|
| Flexibility | Adapt to your needs |
| Accessibility | Include everyone |
```
---
## Using Git for Collaboration
### Daily Workflow
```
Morning:
1. Open Obsidian
- Auto-pulls latest changes
- Shows sync notifications
2. Start editing
During work:
3. Edit articles
4. Add/paste images
5. Preview in Obsidian
Before finishing:
6. Commit changes via Obsidian Git
- Mod+Shift+G → "Commit and Push"
- Or use menu: Obsidian Git → Commit
7. Enter commit message (see examples below)
8. Push to Forgejo
Evening:
9. Optional: Verify changes live on staging/production
```
### Good Commit Messages
**Format:**
```
<type>: <subject>
Optional longer explanation...
```
**Types:**
- `content:` - Article edits
- `new:` - New article
- `images:` - Image additions
- `fix:` - Bug fixes in content
- `meta:` - Frontmatter changes
**Examples:**
```
content: Expand accessibility guide with mental health section
Added section on creating a safe environment for people with anxiety
and depression, including practical accommodations.
---
new: Add case study for Studio XYZ
Documents their transition from traditional to cooperative structure
over 18 months, with lessons learned.
---
images: Add diagrams to conflict resolution guide
Created flowchart for escalation process and decision tree for
choosing resolution approach.
```
### Handling Conflicts
**If you see a conflict:**
1. Open Obsidian
2. Look for `conflict-files-obsidian-git.md` file
3. Find the article with conflict markers:
```markdown
<<<<<<< HEAD
Your version
=======
Their version
>>>>>>> main
```
4. Choose correct version (or merge manually)
5. Remove conflict markers
6. Save
7. Commit: `Conflict resolved: merged changes in article-name.md`
**Prevent conflicts:**
- Pull before starting work
- Work on different articles when possible
- Push frequently (every 30-60 min)
- Communicate about big edits
---
## Keyboard Shortcuts (Recommended)
**Set up in Obsidian Settings → Hotkeys:**
| Action | Mac | Windows |
|--------|-----|---------|
| New file | `Cmd+N` | `Ctrl+N` |
| Quick switcher | `Cmd+O` | `Ctrl+O` |
| Commit & Push | `Mod+Shift+G` | `Mod+Shift+G` |
| Open command palette | `Cmd+P` | `Ctrl+P` |
(These are configured in `.obsidian/hotkeys.json`)
---
## Obsidian Plugins
### Required Plugins (Must Install)
1. **Obsidian Git** - Commit/push directly from Obsidian
- **Status:** Configured but requires manual installation
- **To install:** See "Quick Start → Step 3" above
- **Features:**
- Auto-pulls on startup
- Auto-backup option (disabled to prevent constant commits)
- Settings → Obsidian Git
- **Shortcut:** `Mod+Shift+G` to commit & push
### Optional Plugins (Recommended)
2. **Linter** - Keep markdown formatting consistent
- Helps maintain clean, consistent formatting
- Settings → Linter
- Auto-fixes formatting on save
3. **Templater** - Create article templates
- Create templates for different article types
- Settings → Templater
- Useful if you create many articles of the same type
### Installing Additional Plugins
1. Go to **Settings → Community plugins**
2. Click **"Browse"** to browse community plugins
3. Search for plugin name
4. Click **"Install"** → **"Enable"**
5. Configure settings if needed
---
## Common Issues
### "I don't see the Obsidian Git plugin"
**Problem:** After opening the vault, the Git plugin isn't visible or available
**Root cause:** Plugins are configured in the vault, but need to be manually installed from the Obsidian community plugins browser first.
**Solution:**
1. Go to **Settings → Community plugins**
2. If you see "Turn off restricted mode" - click it first
3. Click **"Browse"** button
4. Search for **"Obsidian Git"** by Vinzent03
5. Click **"Install"**
6. Click **"Enable"**
7. **Restart Obsidian** or reload the vault
8. Check `Obsidian Git` menu → should now show Git options
9. Try commit shortcut: **`Mod+Shift+G`**
**Still not working?**
- Make sure you're not in "Restricted mode"
- Check if Internet connection is working (needed to browse plugins)
- Try restarting Obsidian completely
- See Troubleshooting.md for more help
---
### "Can't find vault"
**Problem:** Obsidian can't open the `/content/articles/` folder
**Solution:**
```bash
# Make sure you're in the right directory
cd /path/to/wiki-ghostguild
ls content/articles/
# Then open Obsidian and use full path:
# Mac: /Users/yourname/Sites/wiki-ghostguild/content/articles/
# Windows: C:\Users\yourname\Sites\wiki-ghostguild\content\articles\
```
### Images not saving
**Problem:** Pasting image doesn't auto-save to `/public/img/`
**Solution:**
1. Check Settings → Files & Links
2. Verify "Attachment folder path": `../../public/img`
3. Make sure folder exists: `ls public/img/`
4. Try again: Paste image with Cmd+V
### Wikilinks not working
**Problem:** `[[Page Name]]` shows as red/broken
**Solutions:**
1. **Check spelling** - Links are exact-match
2. **Check frontmatter title** - Link uses article title, not filename
3. **Restart Obsidian** - Sometimes cache issues
4. **Check graph view** - Obsidian → Tab → Graph to see all pages
### Git conflicts
**Problem:** Can't push because of merge conflict
**Solutions:**
1. Pull first: Obsidian Git → Pull
2. Resolve conflicts (see "Handling Conflicts" above)
3. Commit the resolution
4. Push
### "Port already in use"
**Problem:** `npm run dev` fails with port error
**Solution:**
```bash
# Find and kill the existing dev server
ps aux | grep nuxt
kill -9 <PID>
# Then try again
npm run dev
```
---
## Preview & Testing
### Preview in Obsidian
1. Open any article
2. Toggle preview mode: `Cmd+E` (Mac) or `Ctrl+E` (Windows)
3. See how content looks (but wikilinks won't work - they're transformed at build)
### Test in Browser
```bash
# Start dev server
npm run dev
# Visit: http://localhost:3000/articles/article-slug
# Check that:
# - All wikilinks rendered as clickable links
# - Images display correctly
# - Frontmatter title shows
# - Formatting looks right
```
### Test Before Pushing
```bash
# Run static build
npm run generate
# Preview output
npm run preview
# Visit: http://localhost:3000/articles/article-slug
# This is what production looks like
```
---
## File Structure
What you need to know:
```
wiki-ghostguild/
├── content/articles/ ← You edit files HERE
│ ├── article-one.md
│ ├── article-two.md
│ └── .obsidian/ ← Vault configuration (shared)
├── public/img/ ← Images go HERE (via Obsidian paste)
├── app/ ← Website code (don't edit)
├── app/server/
│ └── plugins/
│ └── wikilink-transform.ts ← Transforms wikilinks & images
└── docs/ ← Documentation
```
---
## Advanced: How Transformation Works
**You don't need to understand this, but here's what happens:**
1. **You write in Obsidian:**
```markdown
[[P0 - Communication Norms]]
![[diagram.jpg]]
```
2. **At build time, the Nitro plugin transforms to:**
```markdown
[Communication Norms](/articles/communication-norms-document-for-game-studios)
![diagram.jpg](/img/diagram.jpg)
```
3. **Readers see proper links:**
- Clicking link → goes to `/articles/communication-norms-document-for-game-studios`
- Image loads from `/img/diagram.jpg` (in /public/)
**Why this approach:**
- ✅ Wikilinks work perfectly in Obsidian
- ✅ Automatic link updates when renaming
- ✅ No runtime overhead (transform at build)
- ✅ Clean web links for readers
---
## Questions?
Check:
1. **Obsidian Help**: https://help.obsidian.md
2. **Obsidian Git Plugin**: https://github.com/Vinzent03/obsidian-git
3. **Technical Docs**: See `docs/TECHNICAL_ARCHITECTURE.md`
4. **Troubleshooting**: See `docs/TROUBLESHOOTING.md`
Or ask your team!
---
**Remember:** The vault is designed to be simple and collaborative. Both users can edit freely, Git handles versioning, and the build transforms everything for the web. Happy writing!

344
docs/README.md Normal file
View file

@ -0,0 +1,344 @@
# Wiki-GhostGuild Documentation
Welcome to the documentation for the wiki-ghostguild content system.
---
## Quick Links
**Starting out?** → Read [`OBSIDIAN_SETUP_GUIDE.md`](./OBSIDIAN_SETUP_GUIDE.md)
**Having problems?** → Check [`TROUBLESHOOTING.md`](./TROUBLESHOOTING.md)
**Want technical details?** → See [`TECHNICAL_ARCHITECTURE.md`](./TECHNICAL_ARCHITECTURE.md)
---
## Documentation Structure
### [OBSIDIAN_SETUP_GUIDE.md](./OBSIDIAN_SETUP_GUIDE.md)
**For:** All content contributors
Everything you need to know about:
- Opening the Obsidian vault
- Writing articles with wikilinks
- Adding images
- Using Git for collaboration
- Common workflows
- Keyboard shortcuts
**Start here if:** You're new to the system or new to the team
---
### [TECHNICAL_ARCHITECTURE.md](./TECHNICAL_ARCHITECTURE.md)
**For:** Technical team members, maintainers
Deep dive into:
- How the system works (Obsidian → Nuxt → Web)
- Wikilink transformation plugin
- Content processing pipeline
- Image handling
- Build process
- Performance characteristics
- Edge cases and future enhancements
**Read this if:** You want to understand how everything works, or you're maintaining the codebase
---
### [TROUBLESHOOTING.md](./TROUBLESHOOTING.md)
**For:** Anyone encountering issues
Practical solutions for:
- Obsidian issues (vault, wikilinks, images, Git)
- Git issues (push, conflicts)
- Build problems
- Deployment issues
- Network issues
- Article problems
**Use this if:** Something isn't working and you need to fix it
---
## System Overview
```
You write in Obsidian Build transforms Web readers see
↓ ↓ ↓
[[Page Title]] → Wikilink Transform → [Title](/articles/slug)
![[image.jpg]] → Image Transform → ![](/img/image.jpg)
(with Git for collaboration)
```
---
## Getting Started (5 minutes)
1. **Clone the repo**
```bash
git clone https://your-forgejo.com/org/wiki-ghostguild.git
cd wiki-ghostguild
npm install
```
2. **Open Obsidian**
- Open vault: `content/articles/`
- Settings auto-load
- Plugins auto-enable
3. **Start editing**
- Open an article
- Make a change
- Git commit via Obsidian Git
- Push
4. **Test locally**
```bash
npm run dev
# Visit http://localhost:3000
```
---
## Key Concepts
### Wikilinks
Obsidian native linking syntax:
```markdown
[[Page Title]]
[[Long Name|Short Text]]
```
**At build:** Transforms to `/articles/slug` format for web
**Why:** Clean in Obsidian, proper links on web
---
### Images
Paste images directly in Obsidian:
```markdown
![[diagram.jpg]]
```
**Saving:** Auto-saves to `/public/img/`
**At build:** Transforms to `/img/filename` format
---
### Collaboration
Both users edit via Obsidian, commit via Git:
1. User A edits → commits → pushes
2. User B pulls → gets User A's changes
3. User B edits → commits → pushes
4. Git handles versioning and conflicts
---
### Frontmatter
Every article starts with metadata:
```yaml
---
title: "Article Title"
description: "Brief description"
category: "accessibility" # or strategy, funding, etc.
tags: [baby-ghosts, p0]
accessLevel: "member" # or public, cohort, admin
author: "Author Name"
publishedAt: '2025-11-10T13:00:00Z'
---
```
**Required:** `title`
**Optional:** Everything else (but frontmatter itself is required)
---
## Common Workflows
### Adding a New Article
1. In Obsidian: `Cmd+N` (new file)
2. Add frontmatter (copy from template or example)
3. Write content using wikilinks
4. Add images (paste with `Cmd+V`)
5. Git: Commit & push
6. Test: `npm run generate` then `npm run preview`
### Updating Existing Article
1. Open article in Obsidian
2. Edit content
3. Update wikilinks if needed
4. Commit with descriptive message
5. Push
### Fixing a Typo
1. Find typo in article
2. Edit
3. Commit: `fix: correct typo in article-name`
4. Push
### Handling a Conflict
1. Pull (Obsidian Git)
2. Look for conflict markers in file
3. Choose correct version
4. Remove markers
5. Save
6. Commit: `Resolve conflict`
7. Push
---
## File Structure
```
wiki-ghostguild/
├── docs/ ← You are here
│ ├── README.md ← Start here
│ ├── OBSIDIAN_SETUP_GUIDE.md ← User guide
│ ├── TECHNICAL_ARCHITECTURE.md ← How it works
│ └── TROUBLESHOOTING.md ← Problem solving
├── content/
│ └── articles/ ← Your content (Obsidian vault)
│ ├── article-one.md
│ ├── article-two.md
│ └── .obsidian/ ← Vault configuration
├── public/
│ └── img/ ← Images (auto-saved by Obsidian)
├── app/
│ └── server/
│ └── plugins/
│ └── wikilink-transform.ts ← Transformation magic
└── package.json
```
---
## Quick Reference
### Commands
```bash
npm run dev # Start dev server (port 3000, hot reload)
npm run generate # Build static site to .output/
npm run preview # Preview built site
npm run build # Build application (if deploying)
git pull # Get latest changes
git add -A # Stage changes
git commit -m "msg" # Commit
git push # Push to Forgejo
```
### Keyboard Shortcuts (Obsidian)
- `Cmd+N` - New file
- `Cmd+O` - Quick switcher (search articles)
- `Cmd+P` - Command palette
- `Cmd+E` - Toggle preview
- `Mod+Shift+G` - Commit & push (via Obsidian Git)
---
## Support
### Finding Help
1. **Check this documentation** - Most answers are here
2. **Search online** - Error message + "Obsidian" or "Nuxt"
3. **Ask your team** - Slack, email, or in person
### Reporting Issues
If you find a bug or have a feature request:
1. **Document it** - What happened? What did you expect?
2. **Check if known** - Look in TROUBLESHOOTING.md
3. **Create issue** - In Forgejo/GitHub
4. **Include context** - OS, error message, steps to reproduce
---
## Maintenance
### Regular Tasks
**Weekly:**
- Run `npm run generate` to check build works
- Review commit messages
**Monthly:**
- Test full workflow
- Check article links (broken link audit)
**Quarterly:**
- Update dependencies (`npm outdated`, `npm update`)
- Review Obsidian plugin updates
---
## FAQ
**Q: Do I need to understand how the transformation works?**
A: No! Just know that:
- Wikilinks work in Obsidian
- They transform to normal links on the web
- Same for images
**Q: Can two people edit at the same time?**
A: Yes! As long as they edit different articles. If you edit the same article, Git will flag a conflict (easy to resolve).
**Q: What if I make a typo and push by accident?**
A: Just fix it and push again. Git tracks history, so you can revert if needed.
**Q: How do I know my changes are live?**
A: After pushing, the server automatically rebuilds and deploys (depends on your CI/CD setup).
**Q: Can I use Obsidian plugins?**
A: Yes! Go to Settings → Community plugins → Browse. Just avoid plugins that modify file structure.
---
## Next Steps
- **New contributor?** Read [OBSIDIAN_SETUP_GUIDE.md](./OBSIDIAN_SETUP_GUIDE.md)
- **Having issues?** Check [TROUBLESHOOTING.md](./TROUBLESHOOTING.md)
- **Want to learn more?** Read [TECHNICAL_ARCHITECTURE.md](./TECHNICAL_ARCHITECTURE.md)
---
## Feedback
Found something unclear? Have a suggestion?
- Comment in a GitHub/Forgejo issue
- Edit the docs (improve them!)
- Ask on the team channel
---
**Last Updated:** November 2025
**Maintained by:** Wiki-GhostGuild Team

View file

@ -0,0 +1,607 @@
# Technical Architecture: Obsidian-Nuxt Integration
**For:** Technical team members, maintainers
---
## System Overview
```
Obsidian Vault (source) Nuxt Content (processing) Web (output)
↓ ↓ ↓
content/articles/*.md → Wikilink Transform Plugin → /articles/slug
with [[links]] (Nitro server plugin) with /articles/ links
with ![[images]] with /img/ references
Image embed transformation
(Nitro server plugin)
Nuxt build generates
Static HTML + JSON
```
---
## Architecture Components
### 1. Obsidian Vault Configuration
**Location:** `/content/articles/.obsidian/`
**Key Files:**
- `app.json` - Settings (attachment folder, link format, etc.)
- `community-plugins.json` - List of plugins to enable
- `hotkeys.json` - Keyboard shortcuts
- `plugins/obsidian-git/data.json` - Git plugin configuration
**Attachment Folder:**
```json
{
"attachmentFolderPath": "../../public/img"
}
```
This tells Obsidian to save images to `/public/img/` instead of keeping them in the vault.
**User-Specific (Gitignored):**
- `workspace.json` - Open files, window layout (per-user)
- `appearance.json` - Theme preferences (per-user)
- `cache/` - Obsidian's internal cache
- `graph.json` - Graph view state
**Shared (Committed):**
- `app.json` - Core settings
- `community-plugins.json` - Plugin list
- `hotkeys.json` - Team shortcuts
---
### 2. Wikilink Transformation Plugin
**Location:** `/app/server/plugins/wikilink-transform.ts`
**Hook:** `content:file:beforeParse`
**Timing:** Runs during Nuxt Content processing, before markdown parsing
**Transformations:**
#### Wikilinks → Markdown Links
```typescript
// Input
[[P0 - Communication Norms for Game Studios]]
[[Grant Writing Guide|Grant Guide]]
// Output
[Communication Norms for Game Studios](/articles/communication-norms-for-game-studios)
[Grant Guide](/articles/grant-writing-guide)
// Logic
1. Strip P0/P1/P2 prefix
2. Convert title to slug (lowercase, spaces→hyphens, special chars→removed)
3. Create markdown link with /articles/ prefix
```
**Slug Generation:**
```typescript
function titleToSlug(title: string): string {
return title
.toLowerCase()
.replace(/['"]/g, '') // Remove quotes
.replace(/&/g, 'and') // & → and
.replace(/[^a-z0-9\s-]/g, '') // Remove special chars
.replace(/\s+/g, '-') // Spaces → hyphens
.replace(/-+/g, '-') // Collapse hyphens
.replace(/^-|-$/g, ''); // Trim edges
}
// Examples:
"Grant Writing & Funding Strategy" → "grant-writing-and-funding-strategy"
"Co-op: Structure & Governance" → "co-op-structure-and-governance"
"Q&A: Funding" → "qa-funding"
```
#### Image Embeds → Markdown Images
```typescript
// Input
![[diagram.jpg]]
![[workflow.png|Team workflow diagram]]
// Output
![diagram.jpg](/img/diagram.jpg)
![Team workflow diagram](/img/workflow.png)
// Logic
1. Extract filename and optional alt text
2. Create markdown image with /img/ prefix
```
---
### 3. Content Processing Pipeline
**Sequence:**
```
1. File read from disk
File: /content/articles/article-name.md
2. content:file:beforeParse hook (OUR PLUGIN)
- Extract wikilinks: [[...]]
- Extract image embeds: ![[...]]
- Transform both to markdown syntax
- Update file.body
3. Frontmatter parsing (gray-matter)
- Extract YAML frontmatter
- Validate against schema
4. Markdown parsing (Nuxt Content)
- Convert markdown to AST
- Generate HTML structure
5. Static generation
- Render article pages
- Create JSON payloads
- Output to .output/
```
**No Markdown Plugins Needed:**
Nuxt Content v3 uses Nuxt's built-in markdown processor. We don't need remark/rehype plugins because the Nitro plugin hook runs before all parsing.
---
### 4. Image Handling
**Storage:** `/public/img/`
**Workflow:**
```
User in Obsidian
Pastes image (Cmd+V)
Obsidian saves to /public/img/
User writes ![[filename.jpg]]
Git add + commit
Image goes to repository
At build:
- Plugin transforms ![[filename.jpg]] → ![...](/img/filename.jpg)
- Build copies /public/img/ to output
Web server serves /img/filename.jpg
```
**Path Resolution:**
When Obsidian saves image from vault at `/content/articles/`:
```
From: /content/articles/some-article.md
To: /public/img/
Relative: ../../public/img
So when you paste in Obsidian, it:
Saves to: /public/img/
Creates: ![image](../../public/img/image.jpg)
```
The transformation plugin converts this to `/img/image.jpg` for web output.
---
### 5. Nuxt Content Collection
**Configuration:** `content.config.ts`
```typescript
export default defineContentConfig({
collections: {
articles: defineCollection({
type: "data",
source: "**/*.md", // Finds all .md files
schema: z.object({
title: z.string(),
description: z.string().optional(),
category: z.string().optional(),
tags: z.array(z.string()).optional(),
author: z.string().optional(),
contributors: z.array(z.string()).optional(),
published: z.boolean().default(true),
featured: z.boolean().default(false),
accessLevel: z.string().optional(),
publishedAt: z.string().optional(),
}),
}),
},
});
```
**Validation:**
- Frontmatter must match schema
- Missing required fields cause build errors
- All fields run through Zod validation
---
### 6. Git Workflow Integration
**Via Obsidian Git Plugin**
**Configuration:** `.obsidian/plugins/obsidian-git/data.json`
```json
{
"autoPullOnBoot": true, // Pull on startup
"autoPullInterval": 5, // Pull every 5 minutes
"disablePush": false, // Allow pushing
"pullBeforePush": true, // Always pull before pushing
"conflictHandlingStrategy": "ask" // Ask on conflicts
}
```
**User Workflow:**
1. **User A** edits article, commits, pushes
2. **User B** starts Obsidian → auto-pulls User A's changes
3. **User B** edits different article → no conflict
4. **User B** commits & pushes
5. **User A** continues working → might pull when prompted
**Conflict Resolution:**
If both users edit same file:
```
1. Pull fails with conflict
2. Obsidian Git creates conflict-files-obsidian-git.md
3. User sees conflict markers in file:
<<<<<<< HEAD
User A's version
=======
User B's version
>>>>>>> main
4. User manually resolves (chooses/merges versions)
5. User commits resolution
6. User pushes
```
---
## Build Process
### Development (`npm run dev`)
```bash
# Starts:
# 1. Nuxt dev server (hot reload)
# 2. Watches /content/articles/ for changes
# 3. When file saves: re-processes & hot-reload in browser
npm run dev
# → http://localhost:3000
# → Changes live-update without refresh
```
### Production (`npm run generate`)
```bash
# Builds static site:
# 1. Processes all content files
# 2. Runs wikilink transformation
# 3. Generates HTML pages + JSON
# 4. Optimizes assets
# 5. Outputs to .output/public/
npm run generate
# → .output/public/ contains complete static site
# → Ready to deploy to CDN/hosting
```
### Static Preview (`npm run preview`)
```bash
# Starts server serving built output:
# Shows what production will look like
npm run preview
# → http://localhost:3000
# → Serves from .output/public/
```
---
## File Mappings
**Article Files → URL Slugs:**
```
Obsidian filename Content title URL slug
────────────────────────────────────────────────────────────────────────
communication-norms*.md Communication Norms Document /articles/communication-norms-document-for-game-studios
meeting-agenda*.md Meeting Agenda & Facilitation /articles/meeting-agenda-facilitation-guide-for-game-studios
co-op-structure*.md Co-op: Structure & Governance /articles/co-op-structure-and-governance
*Actual filename doesn't matter for slug generation
Slug comes from frontmatter title
```
**Why this matters:**
If you rename a file in Obsidian:
- ❌ Obsidian updates internal links automatically (good!)
- ✅ Slug stays same (derived from title, not filename)
- If you change the title in frontmatter: slug changes → URL changes
---
## Performance Characteristics
### Build Times
| Operation | Time | Notes |
|-----------|------|-------|
| Dev server startup | ~10-15s | Nuxt init + content processing |
| Hot reload | ~1-2s | Single file change |
| Full static build | ~30-60s | 42 articles + optimization |
| Content indexing | ~100ms | Build-time caching |
### Runtime Performance
- **No runtime transformation** - All done at build
- **Static HTML output** - Zero processing at serve time
- **Fast first page load** - No client-side rendering for content
### Scaling
- **100 articles** - Build still <60s
- **1000 articles** - Might need optimization (parallel builds)
- **Image count** - No impact (images in /public/, not in content)
---
## Edge Cases & Solutions
### Case Sensitivity
**Problem:** Filenames case-sensitive on Linux, case-insensitive on Mac
**Solution:** Always use lowercase slugs
```yaml
# ✅ Good
- [[Grant Writing Guide]]
- [[case-study-studio-xyz]]
# ❌ Problematic
- [[Grant WRITING Guide]]
- [[Case-Study-Studio-XYZ]]
```
### Special Characters
**In Article Titles:**
```
Input: "Co-op: Structure & Governance"
Slug: "co-op-structure-and-governance"
Input: "Q&A: Funding"
Slug: "qa-funding"
Input: "The "Beginning""
Slug: "the-beginning"
```
**In Image Names:**
```
✅ Good: meeting-workflow-diagram.jpg
❌ Bad: Meeting Workflow Diagram.jpg (spaces)
❌ Bad: image (2).jpg (parentheses)
```
### Circular References
**Not a problem:**
- Article A links to Article B
- Article B links to Article A
- Both work fine (static links, no runtime resolution)
### Non-Existent Links
**Behavior:**
- Wikilink transforms to `/articles/non-existent-page`
- User clicks → sees 404 page
- No build error
**Detection (optional enhancement):**
```typescript
// Could validate at build time:
// - Get all article slugs
// - Check each transformed link
// - Warn if any don't exist
```
---
## Troubleshooting
### Build Fails: "Invalid frontmatter"
**Cause:** File violates schema
**Fix:**
```yaml
# Check:
- Is 'title' present?
- Is YAML syntax valid (spaces not tabs)?
- Are arrays formatted correctly?
# Example invalid:
- tags: baby-ghosts, p0 # ❌ Missing brackets
+ tags: [baby-ghosts, p0] # ✅ Correct array syntax
```
### Wikilinks Showing Literally
**Cause:** Plugin didn't run or had error
**Check:**
```bash
# 1. Restart dev server
npm run dev
# 2. Check plugin file exists
ls app/server/plugins/wikilink-transform.ts
# 3. Check for errors in terminal
# Look for "error TS" messages
# 4. Clear cache
rm -rf .nuxt
npm run dev
```
### Images Not Displaying
**Cause 1:** Image not in `/public/img/`
```bash
# Check:
ls public/img/image.jpg
# If missing, add it:
cp path/to/image.jpg public/img/
git add public/img/image.jpg
```
**Cause 2:** Wrong path in markdown
```markdown
# Check these:
![[image.jpg]] # ✅ Correct (Obsidian syntax)
![](/img/image.jpg) # ✅ Correct (markdown)
![](/public/img/image.jpg) # ❌ Wrong (extra /public/)
```
### Git Conflicts
**Prevention:**
- Pull before editing
- Work on different files
- Push frequently
**Resolution:**
- See OBSIDIAN_SETUP_GUIDE.md → "Handling Conflicts"
---
## Future Enhancements
### Backlinks Display
Show which articles link to current article:
```vue
<div class="backlinks">
<h3>Referenced by:</h3>
<ul>
<li v-for="article in backlinks">
<NuxtLink :to="`/articles/${article.slug}`">
{{ article.title }}
</NuxtLink>
</li>
</ul>
</div>
```
### Link Validation at Build
Fail build if broken wikilinks detected:
```typescript
// In plugin:
const allSlugs = /* get all article slugs */
wikilinks.forEach(link => {
const slug = wikilinkToSlug(link)
if (!allSlugs.includes(slug)) {
throw new Error(`Broken wikilink: ${link}`)
}
})
```
### Graph Visualization
Show article connections as interactive graph:
```
Communication Norms
/ | \
↓ ↓ ↓
M.Guide Peer Support Bylaws
```
---
## Maintenance
### Regular Tasks
**Weekly:**
- Check for broken images (audit script)
- Review commit messages (consistency)
**Monthly:**
- Run full build test (`npm run generate`)
- Test on staging server
- Backup Forgejo repository
**Quarterly:**
- Review plugin versions (Obsidian Git, etc.)
- Update dependencies if needed
### Updating Obsidian Vault Config
Only need to commit `.obsidian/` folder if config changes:
```bash
# Check what changed
git status
# If app.json changed:
git add content/articles/.obsidian/app.json
git commit -m "Update Obsidian vault settings"
git push
# Other users pull and get new settings
```
---
## References
- **Nuxt Content v3:** https://content.nuxt.com
- **Nuxt:** https://nuxt.com
- **Nitro:** https://nitro.unjs.io
- **Obsidian:** https://obsidian.md
- **Obsidian Git:** https://github.com/Vinzent03/obsidian-git
---
**Last Updated:** November 2025
**Maintainer:** Wiki-GhostGuild Team

564
docs/TROUBLESHOOTING.md Normal file
View file

@ -0,0 +1,564 @@
# Troubleshooting Guide
**For:** Wiki-GhostGuild Content Contributors
Common issues and solutions.
---
## Obsidian Issues
### Obsidian Won't Open Vault
**Symptom:** "Vault not found" or error when opening folder
**Solutions:**
1. **Check path:** Make sure you're opening the exact right folder
```bash
# Should be this:
/path/to/wiki-ghostguild/content/articles/
# Not this:
/path/to/wiki-ghostguild/ # Parent folder
/path/to/wiki-ghostguild/content/ # Wrong subfolder
```
2. **Full path issues:** On Mac, use full path starting with `/Users/`
```
/Users/yourname/Sites/wiki-ghostguild/content/articles/
```
3. **Permissions:** Make sure you have read/write access
```bash
ls -ld /path/to/wiki-ghostguild/content/articles/
# Should show: drwxrwxr-x (or similar with r+w)
```
4. **Restart Obsidian:** Close completely and reopen
---
### Wikilinks Showing as Red (Broken)
**Symptom:** `[[Page Name]]` appears in red in Obsidian
**Causes & Solutions:**
1. **Typo in page name**
```
❌ [[Communication Norms]] - Missing full title
✅ [[Communication Norms Document for Game Studios]]
```
→ Links must match article titles exactly
2. **Title in frontmatter doesn't match**
```yaml
# In article file:
---
title: "Communication Norms Document for Game Studios"
---
# Then this works:
[[Communication Norms Document for Game Studios]]
# But this doesn't:
[[Communication Norms]] # Partial match doesn't work
```
3. **Cache issue**
- Close Obsidian completely
- Wait 10 seconds
- Reopen
- Wikilink should show as blue now
4. **Check article exists**
- Open Graph view: Left sidebar → "Graph" tab
- Search for the article title
- If not there, article file is missing or title is wrong
---
### Images Not Saving
**Symptom:** Paste image, nothing appears or goes to wrong location
**Solutions:**
1. **Check attachment folder setting**
- Settings → Files & Links
- "Attachment folder path" should be: `../../public/img`
- If different, change it back
2. **Folder doesn't exist**
```bash
# Check:
ls /path/to/wiki-ghostguild/public/img/
# If not there, create:
mkdir -p /path/to/wiki-ghostguild/public/img/
```
3. **Try again**
- Paste image: `Cmd+V` (Mac) or `Ctrl+V`
- Should prompt for filename
- Edit if needed and confirm
- Image should appear and be saved to `/public/img/`
4. **Check permissions**
```bash
ls -ld /path/to/wiki-ghostguild/public/img/
# Should be writable (w flag)
```
5. **Restart Obsidian**
- Close completely
- Reopen vault
- Try pasting again
---
### Obsidian Git Not Working
**Symptom:** Obsidian Git plugin not appearing or not committing
**Solutions:**
1. **Plugin not enabled**
- Settings → Community plugins
- Search "Obsidian Git"
- Toggle ON if disabled
2. **Restricted mode**
- Settings → Community plugins
- If "Restricted mode ON" shows, click toggle
- Enable plugins
- Refresh
3. **Git not installed**
```bash
# Check if git is available:
which git
# Should show: /usr/bin/git or similar
# If not, install:
# Mac: brew install git
# Windows: Download from git-scm.com
```
4. **Not in git repository**
```bash
# Check:
cd /path/to/wiki-ghostguild
git status
# Should show branch info, not "fatal: not a git repository"
```
5. **Configure git identity**
```bash
git config user.name "Your Name"
git config user.email "your@email.com"
```
6. **Reload plugin**
- Settings → Community plugins → Obsidian Git → Reload
---
## Git Issues
### Can't Push (Remote Rejection)
**Symptom:** "Permission denied" or "rejected" when pushing
**Causes:**
1. Not authenticated to Forgejo
2. Remote URL is wrong
3. Branch is wrong
**Solutions:**
1. **Check remote URL**
```bash
cd wiki-ghostguild
git remote -v
# Should show:
# origin https://your-forgejo.com/org/wiki-ghostguild.git
```
2. **Fix if wrong**
```bash
git remote set-url origin https://your-forgejo.com/org/wiki-ghostguild.git
git push
```
3. **Authenticate to Forgejo**
- Generate personal token (Forgejo settings)
- Use token as password when git prompts
- Or set up SSH key
4. **Check branch**
```bash
git branch
# Should be on 'main' (or whatever default branch)
```
---
### Merge Conflict
**Symptom:** "CONFLICT" in Obsidian Git or error when pulling
**Solutions:**
1. **See conflict file**
- Look for `conflict-files-obsidian-git.md`
- Or use `git status` to see conflicted files
2. **Resolve conflict**
```markdown
# Find conflict markers:
<<<<<<< HEAD
Your version (what you wrote)
=======
Their version (what they wrote)
>>>>>>> main
# Delete one section and keep what's correct
# Or merge both if both are needed
# Remove the markers: <<<<, ====, >>>>
```
3. **After resolving**
```bash
# Mark as resolved
git add file-name.md
# Commit the resolution
git commit -m "Resolve conflict in file-name.md"
# Push
git push
```
4. **Prevent future conflicts**
- **Pull before editing:** Start work each day with `git pull`
- **Work on different files:** If both editing, use different articles
- **Push frequently:** Don't let changes pile up
---
## Building Issues
### Build Fails: "error TS..."
**Symptom:** `npm run generate` shows TypeScript errors
**Solutions:**
1. **Check file syntax**
```bash
# Errors show file path and line number
# Fix the TypeScript error mentioned
```
2. **Clear cache and try again**
```bash
rm -rf .nuxt .output
npm run generate
```
3. **Check dependencies**
```bash
npm install
npm run generate
```
---
### Build Fails: "Invalid frontmatter"
**Symptom:** Build error about article YAML
**Solutions:**
1. **Check YAML syntax**
```yaml
# ✅ Correct syntax
---
title: "My Article"
tags:
- tag1
- tag2
---
# ❌ Common errors
tags: tag1, tag2 # Wrong - should be array with brackets
title: My Article # Missing quotes (usually ok, but can cause issues)
author "Name" # Missing colon
```
2. **Validate YAML online**
- Copy frontmatter to https://www.yamllint.com
- Fix any errors it shows
3. **Check required fields**
```yaml
# Minimum required:
---
title: "Article Title"
---
# All other fields are optional
```
---
### Build Fails: "No such file"
**Symptom:** "Cannot find module" or "ENOENT" error
**Solutions:**
1. **Check file exists**
```bash
ls app/server/plugins/wikilink-transform.ts
ls content.config.ts
```
2. **Check for typos in imports**
- Look at error message for exact path
- Make sure it matches actual file
3. **Reinstall dependencies**
```bash
rm -rf node_modules package-lock.json
npm install
npm run generate
```
---
### Dev Server Slow / Hot Reload Not Working
**Symptom:** Changes take a long time to appear, or don't appear
**Solutions:**
1. **Restart dev server**
```bash
# Stop: Ctrl+C
npm run dev
```
2. **Clear cache**
```bash
rm -rf .nuxt
npm run dev
```
3. **Port conflict**
```bash
# If port 3000 taken:
npm run dev -- -p 3001
# Then visit: http://localhost:3001
```
4. **File too large**
- If a single article is very large (>10,000 lines)
- It may reload slowly
- Consider splitting into multiple articles
---
## Deployment Issues
### Website Shows Old Content
**Symptom:** Changes pushed but don't appear on live site
**Causes:**
1. Build not triggered
2. Cache not cleared
3. Deployment not complete
**Solutions:**
1. **Force rebuild on server**
```bash
cd wiki-ghostguild
git pull
npm run generate
# Restart web server
```
2. **Clear server cache**
- Check hosting provider docs
- Usually: Clear CDN cache or restart server
3. **Check deployment status**
- Look at CI/CD pipeline status
- Check if build completed successfully
---
## Networking Issues
### Can't Clone Repository
**Symptom:** "Permission denied" or authentication fails
**Solutions:**
1. **Set up SSH key (recommended)**
```bash
ssh-keygen -t ed25519 -C "your@email.com"
# Add public key to Forgejo settings
git clone git@your-forgejo.com:org/wiki-ghostguild.git
```
2. **Or use HTTPS with token**
```bash
# Generate personal token in Forgejo
git clone https://your-forgejo.com/org/wiki-ghostguild.git
# Use token as password when prompted
```
3. **Internet connection**
- Check you have internet
- Try `ping google.com`
---
### Port Already in Use
**Symptom:** `npm run dev` fails with "port already in use"
**Solutions:**
```bash
# Find what's using the port
ps aux | grep nuxt
ps aux | grep node
# Kill the process (replace 12345 with PID)
kill -9 12345
# Or use different port
npm run dev -- -p 3001
```
---
## Article Issues
### Frontmatter Missing After Editing
**Symptom:** Content looks corrupted in Obsidian
**Solutions:**
1. **Check file**
```bash
head -20 content/articles/article-name.md
# Should start with:
# ---
# title: ...
```
2. **Recover from git**
```bash
git checkout content/articles/article-name.md
# Reverts to last committed version
```
3. **Check git status**
```bash
git status
# Should show what's changed
```
---
### Article Not Appearing in List
**Symptom:** Article is in /content/articles/ but doesn't show up
**Solutions:**
1. **Check frontmatter**
```yaml
---
title: "Article Title"
published: true # Must be true or missing (default true)
---
```
2. **Check accessibility**
```yaml
# If accessLevel is wrong, won't show:
accessLevel: "member" # User must be logged in
# Try public for testing:
accessLevel: "public"
```
3. **Check file saved**
```bash
git status
# If file shows modified, haven't committed yet
```
4. **Rebuild**
```bash
npm run generate
npm run preview
# Check at http://localhost:3000
```
---
## Getting More Help
If not in this guide:
1. **Check the docs:**
- `OBSIDIAN_SETUP_GUIDE.md` - User guide
- `TECHNICAL_ARCHITECTURE.md` - How it works
2. **Check error message:**
- Copy exact error
- Search online
- Try suggestion from error
3. **Check logs:**
```bash
npm run dev 2>&1 | tee build.log
# Look for warnings/errors
# Look for file paths that don't exist
```
4. **Ask team:**
- Slack/Discord
- Comment in pull request
- Email team lead
---
**Remember:** Most issues are related to:
- ❌ Wrong folder path
- ❌ Missing git configuration
- ❌ Typo in article title
- ❌ Stale cache
99% of the time, one of these fixes it:
1. `rm -rf .nuxt && npm run dev`
2. `git pull`
3. `npm install`
4. Restart Obsidian
5. Restart terminal
---
**Last Updated:** November 2025

91
dokploy.yaml Normal file
View file

@ -0,0 +1,91 @@
# DokPloy Configuration for Wiki.GhostGuild.org
name: wiki-ghostguild
type: nixpacks
# Build Configuration
build:
dockerfile: null # Using Nixpacks auto-detection
context: .
# Environment Configuration
env:
NODE_ENV: production
NITRO_PRESET: node-server
# Secrets (configured in DokPloy UI)
# These should be set in DokPloy interface, not in this file:
# - MONGODB_URI
# - JWT_SECRET
# - JWT_REFRESH_SECRET
# - GHOSTGUILD_CLIENT_ID
# - GHOSTGUILD_CLIENT_SECRET
# - GHOSTGUILD_API_KEY
# Port Configuration
ports:
- 3000:3000
# Health Check
healthcheck:
path: /api/health
interval: 30
timeout: 10
retries: 3
# Resource Limits
resources:
limits:
memory: 1GB
cpu: 1
requests:
memory: 512MB
cpu: 0.5
# Domains
domains:
- wiki.ghostguild.org
# SSL Configuration
ssl:
enabled: true
provider: letsencrypt
email: admin@ghostguild.org
# Deployment Strategy
deploy:
replicas: 1
strategy: rolling
maxSurge: 1
maxUnavailable: 0
# Volume Mounts (for persistent data)
volumes:
- name: content
path: /app/content
size: 5GB
- name: uploads
path: /app/public/uploads
size: 10GB
# Commands
scripts:
prebuild: |
echo "Installing dependencies..."
npm ci
build: |
echo "Building application..."
npm run build
start: |
echo "Starting production server..."
node .output/server/index.mjs
# Monitoring
monitoring:
enabled: true
metrics_path: /metrics
# Backup Configuration
backup:
enabled: true
schedule: "0 2 * * *" # Daily at 2 AM
retention: 30 # Keep 30 days of backups

66
nginx.conf Normal file
View file

@ -0,0 +1,66 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 20M;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript
application/x-javascript application/xml+rss
application/javascript application/json;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Health check endpoint
location /api/health {
access_log off;
add_header Content-Type application/json;
return 200 '{"status":"ok"}';
}
# Static files
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML files - no cache
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate";
}
# SPA fallback - route all unmatched requests to index.html
location / {
try_files $uri $uri/ /index.html;
}
}
}

8
nixpacks.toml Normal file
View file

@ -0,0 +1,8 @@
[phases.install]
commands = ["npm install --ignore-scripts", "npm rebuild"]
[phases.build]
commands = ["npm run postinstall", "npm run build"]
[variables]
OXCPARSER_SKIP_NATIVE_BINDING="1"

53
nuxt.config.ts Normal file
View file

@ -0,0 +1,53 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
future: {
compatibilityVersion: 4,
},
srcDir: "app/",
compatibilityDate: "2024-11-01",
devtools: { enabled: true },
modules: ["@nuxt/content", "@nuxt/ui", "nuxt-auth-utils", "@vueuse/nuxt"],
runtimeConfig: {
// Private runtime config (server-side only)
mongodbUri:
process.env.MONGODB_URI || "mongodb://localhost:27017/wiki-ghostguild",
jwtSecret: process.env.JWT_SECRET || "your-secret-key-change-in-production",
ghostguildApiUrl:
process.env.GHOSTGUILD_API_URL || "https://ghostguild.org/api",
ghostguildApiKey: process.env.GHOSTGUILD_API_KEY || "",
ghostguildClientId: process.env.GHOSTGUILD_CLIENT_ID || "",
ghostguildClientSecret: process.env.GHOSTGUILD_CLIENT_SECRET || "",
// Public runtime config (client-side)
public: {
siteUrl: process.env.SITE_URL || "https://wiki.ghostguild.org",
siteName: "Ghost Guild Knowledge Commons",
siteDescription:
"Collaborative knowledge base for the Baby Ghosts community",
},
},
nitro: {
experimental: {
wasm: true,
},
prerender: {
routes: ["/", "/articles", "/articles/new"],
},
},
typescript: {
strict: true,
typeCheck: true,
},
css: ["~/assets/css/main.css"],
vite: {
build: {
minify: "esbuild",
},
},
});

15050
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

38
package.json Normal file
View file

@ -0,0 +1,38 @@
{
"name": "wiki-ghostguild",
"private": true,
"type": "module",
"engines": {
"node": "^20.19.0"
},
"scripts": {
"build": "nuxt generate",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"start": "node .output/server/index.mjs",
"postinstall": "nuxt prepare || true"
},
"dependencies": {
"@nuxt/content": "^3.7.1",
"@nuxt/ui": "^3.3.7",
"@tailwindcss/typography": "^0.5.19",
"@types/jsonwebtoken": "^9.0.10",
"@types/marked": "^5.0.2",
"@types/mongoose": "^5.11.96",
"@vueuse/nuxt": "^14.0.0",
"better-sqlite3": "^12.4.1",
"jsonwebtoken": "^9.0.2",
"marked": "^17.0.0",
"mongoose": "^8.19.3",
"nuxt": "^4.2.1",
"nuxt-auth-utils": "^0.5.25",
"vue": "^3.5.22",
"vue-router": "^4.6.3"
},
"devDependencies": {
"@types/node": "^24.10.0",
"typescript": "^5.9.3",
"vue-tsc": "^3.1.3"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

11
public/img/.gitkeep Normal file
View file

@ -0,0 +1,11 @@
# Image directory
# Images are stored here and referenced from articles via /img/filename
# Users can add images by:
# 1. Opening /content/articles/ as Obsidian vault
# 2. Pasting images in articles (auto-saves here)
# 3. Or manually adding images to this directory
# Naming convention:
# - Use lowercase, hyphens (not spaces)
# - Example: article-diagram.jpg

2
public/robots.txt Normal file
View file

@ -0,0 +1,2 @@
User-Agent: *
Disallow:

39
scripts/audit-images.sh Executable file
View file

@ -0,0 +1,39 @@
#!/bin/bash
# Audit script to identify missing image references
echo "=== Image Reference Audit ==="
echo ""
echo "Finding all image references in articles..."
echo ""
REFS=$(grep -rh '!\[' content/articles/ 2>/dev/null | grep -oE '\(/img/[^)]+\)' | sed 's/(//' | sed 's/)//' | sort -u)
echo "Total image references found: $(echo "$REFS" | wc -l)"
echo ""
echo "Checking which exist in /public/img/:"
echo ""
MISSING_COUNT=0
EXISTING_COUNT=0
while read -r ref; do
if [ -z "$ref" ]; then continue; fi
filename=$(basename "$ref")
fullpath="/Users/jennie/Sites/wiki-ghostguild${ref}"
if [ -f "$fullpath" ]; then
echo "$filename"
((EXISTING_COUNT++))
else
echo "✗ MISSING: $filename"
((MISSING_COUNT++))
fi
done <<< "$REFS"
echo ""
echo "=== Summary ==="
echo "Existing images: $EXISTING_COUNT"
echo "Missing images: $MISSING_COUNT"
echo ""
echo "Missing images need to be added to /public/img/ or updated in article markdown."

22
tailwind.config.ts Normal file
View file

@ -0,0 +1,22 @@
import type { Config } from "tailwindcss";
import defaultTheme from "tailwindcss/defaultTheme";
import typography from "@tailwindcss/typography";
export default {
content: [
"./components/**/*.{js,vue,ts}",
"./layouts/**/*.vue",
"./pages/**/*.vue",
"./plugins/**/*.{js,ts}",
"./app.vue",
"./error.vue",
],
theme: {
extend: {
fontFamily: {
sans: ["Inter var", ...defaultTheme.fontFamily.sans],
},
},
},
plugins: [typography],
} satisfies Config;

4
tsconfig.json Normal file
View file

@ -0,0 +1,4 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
}