Skip to content

Commit

Permalink
Automating cover image
Browse files Browse the repository at this point in the history
  • Loading branch information
4lejandrito committed Nov 1, 2022
1 parent 83811e0 commit d9bdb48
Show file tree
Hide file tree
Showing 21 changed files with 288 additions and 133 deletions.
18 changes: 18 additions & 0 deletions cover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const puppeteer = require('puppeteer')

;(async () => {
const browser = await puppeteer.launch()
try {
const page = await browser.newPage()
async function shoot(path, query = '') {
await page.goto(`http://creepyface.io/cover?seed=7&${query}`)
await page.waitForSelector('.loaded')
const element = await page.$('.cover')
await element.screenshot({ path })
}
await shoot('cover.jpg', 'small=true')
await shoot('packages/creepyface-site/public/logo.jpg')
} finally {
await browser.close()
}
})()
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"husky": "^8.0.1",
"lerna": "^5.5.0",
"lint-staged": ">=13.0.3",
"prettier": "^2.7.1"
"prettier": "^2.7.1",
"puppeteer": "^19.2.0"
},
"lint-staged": {
"*.{js,ts,tsx,md,json,html,css,scss,webmanifest}": "prettier --write"
Expand Down
79 changes: 42 additions & 37 deletions packages/creepyface-site/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import noBounce from 'no-bounce'
import '@fortawesome/fontawesome-svg-core/styles.css'
import { config } from '@fortawesome/fontawesome-svg-core'
import { Namespace } from '../src/util/namespaces'
import { defaultTheme, Theme } from '../src/util/theme'
import ThemeProvider from '../src/components/Theme'
config.autoAddCss = false

export default function MyApp({
Component,
pageProps,
}: AppProps<{ namespace: Namespace | null }>) {
}: AppProps<{ namespace: Namespace | null; theme?: Theme }>) {
const title = 'Creepyface'
const description =
'The JavaScript library that makes your face look at the pointer'
Expand All @@ -28,43 +30,46 @@ export default function MyApp({
return (
<PlausibleProvider domain="creepyface.io">
<StateProvider namespace={pageProps.namespace}>
<Head>
<meta
name="viewport"
content="width=device-width,initial-scale=1,shrink-to-fit=no"
<ThemeProvider theme={pageProps.theme ?? defaultTheme}>
<Head>
<meta
name="viewport"
content="width=device-width,initial-scale=1,shrink-to-fit=no"
/>
<link rel="icon" href="/favicon.ico" />
<link
href="logo-sm.png"
rel="icon"
sizes="512x512"
type="image/png"
/>
</Head>
<script src="/creepyface.js" />
<NextSeo
title={title}
description={description}
openGraph={{
url: baseURL,
title,
description,
images: [
{
url: `${baseURL}/logo.jpg`,
alt: `Creepyface logo on a background full of faces looking at the pointer`,
},
],
site_name: 'creepyface.io',
}}
twitter={{
handle: '@4lejandrito',
site: '@creepyface_io',
cardType: 'summary_large_image',
}}
additionalMetaTags={[{ name: 'theme-color', content: '#148f77' }]}
/>
<link rel="icon" href="/favicon.ico" />
<link
href="logo-sm.png"
rel="icon"
sizes="512x512"
type="image/png"
/>
</Head>
<script src="/creepyface.js" />
<NextSeo
title={title}
description={description}
openGraph={{
url: baseURL,
title,
description,
images: [
{
url: `${baseURL}/logo.jpg`,
alt: `Creepyface logo on a background full of faces looking at the pointer`,
},
],
site_name: 'creepyface.io',
}}
twitter={{
handle: '@4lejandrito',
site: '@creepyface_io',
cardType: 'summary_large_image',
}}
additionalMetaTags={[{ name: 'theme-color', content: '#148f77' }]}
/>
<Component {...pageProps} />

<Component {...pageProps} />
</ThemeProvider>
</StateProvider>
</PlausibleProvider>
)
Expand Down
71 changes: 57 additions & 14 deletions packages/creepyface-site/pages/cover.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,65 @@
import React from 'react'
import classNames from 'classnames'
import { Point } from 'creepyface'
import { GetServerSideProps, InferGetServerSidePropsType } from 'next'
import React, { useCallback, useEffect, useState } from 'react'
import CreepyFaces from '../src/components/CreepyFaces'
import Logo from '../src/components/Logo'
import useImperativePointProvider from '../src/hooks/imperative'
import { smallImageSize } from '../src/util/constants'
import knuthShuffle from 'knuth-shuffle-seeded'
import range from 'lodash.range'

// Use 1080 * 540
export default function Cover() {
export const getServerSideProps: GetServerSideProps<{
rows: number
cols: number
seed: number
}> = async (context) => ({
props: {
rows: context.query.small === 'true' ? 4 : 6,
cols: 12,
seed: parseInt((context.query.seed as string) ?? '0'),
},
})

export default function Cover(
props: InferGetServerSidePropsType<typeof getServerSideProps>
) {
const { rows, cols, seed } = props
const [lastPoint, setLastPoint] = useState<Point>()
const [pointProvider, setPoint] = useImperativePointProvider()
const [loaded, setLoaded] = useState(false)

useEffect(() => {
if (loaded && lastPoint) {
setPoint(lastPoint)
}
}, [loaded, lastPoint, setPoint])

return (
<>
<style jsx global>{`
.logo {
width: 56vw;
position: relative;
transform: translateY(-24%);
}
`}</style>
<CreepyFaces timeToDefault={0} points={pointProvider} fullscreen dim />
<Logo onPointerPositionChange={setPoint} />
</>
<div
className={classNames('cover', { loaded })}
style={{ width: cols * smallImageSize, height: rows * smallImageSize }}
>
<CreepyFaces
timeToDefault={0}
points={pointProvider}
fullscreen
dim
shuffle
getIds={useCallback(
(size: number, total: number) => {
const ids = knuthShuffle(
range(total - 1).map((i) => i + 1),
seed
)
ids[(Math.floor(rows / 2) - 2) * cols + 5] = 0
return ids.slice(0, size)
},
[rows, cols, seed]
)}
onLoad={useCallback(() => setLoaded(true), [])}
/>
<Logo simple onPointerPositionChange={setLastPoint} />
</div>
)
}
5 changes: 2 additions & 3 deletions packages/creepyface-site/pages/create.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { GetStaticProps } from 'next'
import Home from '.'
import { getHomeGetStaticProps } from '../src/backend/api'

export const getStaticProps: GetStaticProps<React.ComponentProps<typeof Home>> =
async () => ({ props: { create: true } })
export const getStaticProps = getHomeGetStaticProps(true)

export default Home
10 changes: 8 additions & 2 deletions packages/creepyface-site/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@ import { useSelector } from '../src/components/State'
import { changePointProvider } from '../src/redux/actions'
import Footer from '../src/components/Footer'
import CreateButton, { CreateProvider } from '../src/components/CreateButton'
import { getHomeGetStaticProps } from '../src/backend/api'
import { InferGetStaticPropsType } from 'next'

export default function Home({ create = false }) {
export const getStaticProps = getHomeGetStaticProps(false)

export default function Home(
props: InferGetStaticPropsType<typeof getStaticProps>
) {
const translate = useTranslate()
const pointProvider = useSelector((state) => state.pointProvider)
const pointProviderClassName = (name: string) =>
pointProvider === name ? 'selected' : undefined
return (
<CreateProvider open={create} navigate>
<CreateProvider open={props.create} navigate>
<section className="description">
<header>
<Logo />
Expand Down
2 changes: 1 addition & 1 deletion packages/creepyface-site/pages/mosaic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default function Mosaic() {
<small className="powered-by">
{translate('powered by')}{' '}
<Link href="/" target="_blank">
<Logo />
<Logo simple />
</Link>
</small>
{selectedCreepyface !== undefined && (
Expand Down
20 changes: 18 additions & 2 deletions packages/creepyface-site/src/backend/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
GetServerSideProps,
GetServerSidePropsContext,
GetStaticProps,
NextApiHandler,
NextApiRequest,
} from 'next'
Expand All @@ -9,6 +10,7 @@ import auth from 'basic-auth'
import resolve from 'browser-resolve'
import prisma from '../../prisma'
import { Namespace, namespaces } from '../util/namespaces'
import { getTheme, Theme } from '../util/theme'

export const route = (handler: NextApiHandler): NextApiHandler => {
return async (req, res) => {
Expand Down Expand Up @@ -72,15 +74,29 @@ const getNamespace = (context: GetServerSidePropsContext) =>
(context.params?.['namespace'] ?? context.query?.['namespace']) as string
] ?? null

export const getHomeGetStaticProps =
(
create: boolean
): GetStaticProps<{
create: boolean
theme: Theme
}> =>
async () => ({ props: { create, theme: getTheme() }, revalidate: 3600 })

export const getMandatoryNamespaceServerSideProps: GetServerSideProps<{
namespace: Namespace
theme: Theme
}> = async (context) => {
const namespace = getNamespace(context)
return namespace ? { props: { namespace } } : { notFound: true }
return namespace
? { props: { namespace, theme: namespace?.theme ?? getTheme() } }
: { notFound: true }
}

export const getNamespaceServerSideProps: GetServerSideProps<{
namespace: Namespace | null
theme: Theme
}> = async (context) => {
return { props: { namespace: getNamespace(context) } }
const namespace = getNamespace(context)
return { props: { namespace, theme: namespace?.theme ?? getTheme() } }
}
2 changes: 2 additions & 0 deletions packages/creepyface-site/src/components/CreepyFace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export function AsyncCreepyFace(props: {
getImages: (id: number) => Promise<Images | null>
onClick?: () => void
onLongPress?: () => void
onLoad?: () => void
}) {
const [images, setImages] = useState<Images | null>(null)
const isMounted = useMountedState()
Expand All @@ -102,6 +103,7 @@ export function AsyncCreepyFace(props: {
timeToDefault={props.timeToDefault}
onClick={props.onClick}
onLongPress={props.onLongPress}
onLoad={props.onLoad}
/>
)
}
Expand Down
14 changes: 12 additions & 2 deletions packages/creepyface-site/src/components/CreepyFaces.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { memo } from 'react'
import React, { memo, useCallback, useRef } from 'react'
import { AsyncCreepyFace } from './CreepyFace'
import classNames from 'classnames'
import useSpritemap from '../hooks/spritemap'
Expand All @@ -19,11 +19,13 @@ export default memo(function CreepyFaces(props: {
showControls?: boolean
shuffle?: boolean
timeToDefault?: number
getIds?: (size: number, total: number) => number[]
onControls?: (controls?: Controls) => void
onCount?: (count: number) => void
onReload?: (reload: () => void) => void
onSelect?: (id: number) => void
onSelectMany?: (ids: number[]) => void
onLoad?: () => void
}) {
const { cols, rows, size, ref } = useGrid(props.fullscreen)
const { getImages, count } = useSpritemap(
Expand All @@ -35,10 +37,17 @@ export default memo(function CreepyFaces(props: {
rows * cols,
count,
props.shuffle,
props.onControls
props.onControls,
props.getIds
)
const selection = useSelection(ids, props.selectedIds, props.onSelectMany)
const translate = useTranslate()
const loadedRef = useRef(0)
const { onLoad } = props
const onCreepyfaceLoad = useCallback(() => {
if (++loadedRef.current === ids.length) onLoad?.()
}, [onLoad, ids])

return (
<div
ref={ref}
Expand Down Expand Up @@ -80,6 +89,7 @@ export default memo(function CreepyFaces(props: {
(props.onSelect ? () => props.onSelect?.(id) : undefined)
}
onLongPress={selection.onLongPress?.(id)}
onLoad={onCreepyfaceLoad}
/>
)}
</li>
Expand Down
9 changes: 5 additions & 4 deletions packages/creepyface-site/src/components/Logo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const Pointer = (props: {
}

export default function Logo(props: {
simple?: boolean
onPointerPositionChange?: (position: Point) => void
}) {
const [animating, setAnimating] = useState(false)
Expand All @@ -45,8 +46,8 @@ export default function Logo(props: {
<div className="wrapper">
<svg
className={animating ? ' animate' : ''}
onMouseEnter={() => setAnimating(true)}
onClick={() => setAnimating(true)}
onMouseEnter={!props.simple ? () => setAnimating(true) : undefined}
onClick={!props.simple ? () => setAnimating(true) : undefined}
onAnimationEnd={() => setAnimating(false)}
viewBox={`0 0 317.8 78`}
xmlns="http://www.w3.org/2000/svg"
Expand Down Expand Up @@ -135,7 +136,7 @@ export default function Logo(props: {
/>
</g>
</svg>
{theme.name && (
{!props.simple && theme.name && (
<small className="subtitle">
{locale === 'es' && 'Edición '}
<strong>
Expand All @@ -144,7 +145,7 @@ export default function Logo(props: {
{locale === 'en' && ' edition'}
</small>
)}
{theme.hat && (
{!props.simple && theme.hat && (
<img
style={{
top: `${theme.hat.top}%`,
Expand Down

0 comments on commit d9bdb48

Please sign in to comment.