@feugene/granularity-media
v0.7.12026-08-27
Fixed
- Development warnings never reached the browser: the
__GR_DEV__guard included atypeof processcheck, andprocessis undefined in the browser, so the whole expression collapsed tofalsein development too. The guard now matches the core package. Production bundles are unaffected — the branch is still dropped.
v0.7.02026-08-27
Changed
-
Peer floors on
@feugene/*raised to the current minor. Every peer this package declares on the ecosystem now starts at the version the monorepo actually ships:@feugene/fint-i18n→>=0.7.0 <1.0.0@feugene/granularity→>=0.36.0 <1.0.0@feugene/unocss-preset-granular→>=0.13.0 <1.0.0@feugene/unplugin-granularity→>=0.7.0 <1.0.0
The floors had drifted far behind — some still admitted releases from a year of development ago — and a range that claims support it was never tested against is worse than a narrow one: the install succeeds and the breakage surfaces later, in the consumer’s app.
This is breaking for anyone below a floor. Installing against an older
@feugene/granularitynow produces a peer conflict instead of silence. The fix is to move the core up; nothing in this package’s own API changed.
v0.6.12026-08-25
Fixed
-
The package tarball now ships
LICENSE. The manifest has always declared"license": "SEE LICENSE IN LICENSE", and the file it points at was not there:npmaddsLICENSEto a tarball on its own, but only when the file exists in the package directory. A consumer’s compliance scanner reads a licence reference that resolves to nothing and flags the dependency as unlicensed — a refusal on formal grounds, before anyone reads the terms.The copy is byte-identical to the one at the repository root and is kept that way by
yarn check:licenses, a gate in CI: eleven copies of a 598-line file drift silently, and they drift exactly when the licence text is being edited.
v0.6.02026-08-24
Added
GrVideoPlayer— video with controls of its own. Nativecontrolslook different in every browser and know nothing about the design system’s themes or sizes; these are drawn from tokens.- Full screen is requested on the frame, not on
<video>. Asking the video element hands the browser its own interface — our buttons, labels and keyboard would disappear exactly when they are needed most. - The buffered bar takes the range around the current position. Browsers keep several loaded ranges, and after seeking backwards the last one belongs to a different part of the clip: a bar drawn from it would jump ahead and promise data that is not there.
- Duration is not always known. A stream recorded by
MediaRecorder, or a live one, carries no duration in its header and the browser reportsNaN. The progress bar is then not drawn at all and the label shows just the current time — “1:05 / 0:00” would promise an end the recording does not have. - Time is announced in words.
aria-valuetextreads “1:05 / 2:00”; a barearia-valuenowwould say “65 of 120” — correct and useless.
This completes the package: cropping, camera capture, code scanning and playback.
v0.5.02026-08-24
Fixed
GrImageCropcropped a frame other than the one on screen. The window’s height was computed aswidth / aspectRatiowhile the real height comes from CSS —aspect-ratioplus the border, and underbox-sizing: border-boxthe gap is systematic. The window is now measured, both sides, and measured again after the image loads: the frame only takes its ratio together with the image, so the first measurement lands on a transitional height.- A resize now reports a changed frame. Responsive layouts resize the window without the user
touching anything, and the first measurement arrives after
load; a consumer building a file from the previous frame would get something other than what is on screen.
Changed
- Zoom works without
v-model:zoom.zoomwas a controlled prop with no internal state, so the built-in slider was dead for everyone who had not wired the model — which is the common case. The component now keeps its own zoom and lets the prop override it, the same contract the core’s overlays use forv-model:open.
v0.4.02026-08-24
Added
GrCodeScanner— reading QR and barcodes with the camera. What leaves the component is a string, not a file; the frame is never stored.- No decoder ships with the package.
BarcodeDetectorexists in Chrome and Edge but in neither Safari nor Firefox — i.e. not on iPhone at all, which is where scanning mostly happens. Bundling a decoder would force the heaviest dependency in the package on everyone, including those who only took the cropper, so the native path is built in and everything else is covered by adetectorthe application passes; the component page carries a ready recipe. “Nothing can read codes here” is its own state: telling the user to “allow the camera” would send them to solve the wrong problem. - One code in frame is one event. The camera yields dozens of frames per second and the same
code is recognised in each; unfiltered, an application would place twenty orders instead of one.
continuouslifts the filter for goods-in, where identical packages are scanned in a row. The symbology is part of a code’s identity: the same digits asqr_codeand asean_13are two different codes.
Changed
- Camera plumbing — permission, refusal states, frame ratio, stopping tracks — moved into a shared
composable used by both
GrCameraCaptureandGrCodeScanner. Written twice, it would have drifted apart on the first fix.
v0.3.02026-08-23
Changed
GrCameraCaptureno longer crops. Cameras on different devices hand back different sizes and ratios, so fitting the frame to a fixed window is meaningless — one phone would lose the sides, another the top. The photo is now taken whole, in the camera’s own proportions, and the preview frame follows the stream. Cropping to a required shape is the next step, not this component:GrImageCropdoes it on the captured file.aspectRatiobecame a request to the camera rather than a crop. It goes intogetUserMediaasideal, so a device that can produce it will; one that cannot returns its own, and that is what gets shown and captured.exactis deliberately not used: it raisesOverconstrainedError, i.e. reports “no camera” for a perfectly good camera with a different ratio.outputis a bounding box, not an exact size. With both sides given, the frame is fitted inside them and keeps its proportions; taking the numbers literally stretched the picture whenever the ratios disagreed.GrImageCropfollows the same rule.
Removed
cameraFrameRectandGrCameraFrameRect— the centre-crop helper has no callers left, and a dead utility in the public surface is worse than none: it invites use.
v0.2.22026-08-23
Fixed
- A single side in
outputno longer stretches the result. Asking for one dimension is the common case — “an avatar 800 wide” — and the other was taken from the source area instead of being derived from its ratio: a 640×480 camera frame atwidth: 800produced an 800×480 canvas, an image stretched a quarter wider than reality. BothGrCameraCaptureandGrImageCropwere affected; the calculation now lives in one place and is covered on its own.
Earlier versions
The bodies of these releases are not shown: the full feed weighs more than a page is allowed to. The file in the repository is always complete.
v0.2.12026-08-23v0.2.02026-08-23v0.1.02026-08-23